Browsing:

Tag: NoSQL

Getting started with ASP.NET API with MongoLab part 3

This is the sequel to this post
We will be using MongoLab as a backend for our Web Api.

We are using the AddressBook again in this example, but for clarity we're building it from scratch.

Creating the MongoLab database

Head over to MongoLab and create an account!

  • First create a new database. Make sure you choose the free plan. Name the database 'addressbook'.
  • Click to create a new user.
  • Add a new collection (equivalent for a table) named persons.

Please take note of the connectionstring:

2013-11-01 08_12_03-MongoLab_ MongoDB-as-a-Service

Setting up the Web Api project in Visual Studio

Fire up Visual Studio 2013 and hit File -> New -> Project.
Choose Empty ASP.NET Web Application with a Web API and name the project AddressBook.

2013-11-01 08_07_48-New ASP.NET Project - AddressBook

We must install the Mongo Csharp Driver:

Install-Package MongoCsharpDriver

Now open App_Start\WebApiConfig.cs and add json formatting to it (see my previous post why):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace AddressBook
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

//This section you need to add:
            var json = config.Formatters.JsonFormatter;
            json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
            config.Formatters.Remove(config.Formatters.XmlFormatter);
        }
    }
}

Connecting to the MongoLab

Let's not reinvent the wheel if you don't have to. This article is a great introduction to Mongo and C#. I borrowed their MongoConnectionHandler.

using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AddressBook
{
    public class MongoConnectionHandler
    {
        public MongoCollection MongoCollection { get; private set; }

 public MongoConnectionHandler()
        {
            const string connectionString = "mongodb://:@ds031108.mongolab.com:31108/addressbook";
            //const string connectionString = "mongodb://localhost:27017";
            //// Get a thread-safe client object by using a connection string
            var mongoClient = new MongoClient(connectionString);

            //// Get a reference to a server object from the Mongo client object
            var mongoServer = mongoClient.GetServer();

            //// Get a reference to the database object 
            //// from the Mongo server object
            const string databaseName = "persons";
            var db = mongoServer.GetDatabase(databaseName);

            //// Get a reference to the collection object from the Mongo database object
            //// The collection name is the type converted to lowercase + "s"
            MongoCollection = db.GetCollection(typeof(T).Name.ToLower() + "s");
        }
    }
}

The Person class

I want the Person_Id to be the same as the document id, so I can retrieve documents easily. I'm not sure though if this is best practice. But it works.

public class Person 
    {
        public Person()
        {
            Person_Id = ObjectId.GenerateNewId().ToString();
        }

        [BsonId]
        public string Person_Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Phone { get; set; }
        public string Email { get; set; }
        public string Blog { get; set; }
        public string Facebook { get; set; }
        public string Twitter { get; set; }
        public string LinkedIn { get; set; }
        public string Googleplus { get; set; }
    }

And here's the POST method:

public class PersonController : ApiController
    {
        public MongoConnectionHandler collection = new MongoConnectionHandler();

        public HttpResponseMessage Post([FromBody] Person person)
        {
            collection.MongoCollection.Insert(person);
            var response = Request.CreateResponse(HttpStatusCode.Created, person);

          
            string uri = Url.Link("DefaultApi", new { id = person.Person_Id });
            response.Headers.Location = new Uri(uri);
            return response;

        }


    }
      

You can use the API with Fiddler.

2013-11-01 14_33_36-Fiddler Web Debugger

Look at the results it has returned:

2013-11-01 14_35_25-Fiddler Web Debugger

It returned the new URI with the new Id as you can see.

Now let's check MongoLab, and lo and behold:

2013-11-01 14_39_53-MongoLab_ MongoDB-as-a-Service

Here's the remainder of the CRUD methods:

        public IEnumerable Get()
        {
            return collection.MongoCollection.FindAll().AsEnumerable();

        }


        public Person Get(string id) {

            //var query = Query.EQ(p => p.Person_Id, id);
            return collection.MongoCollection.FindOne(Query.EQ("_id", id));

        }

        public void Delete(string id)
        {
            collection.MongoCollection.Remove(Query.EQ("_id", id));

        }

        public HttpResponseMessage Put([FromBody] Person person)
        {
            
            var p = collection.MongoCollection.FindOne(Query.EQ("_id", person.Person_Id));

            if (p != null)
            {
                collection.MongoCollection.Save(person);
            }
           
            return Request.CreateResponse(HttpStatusCode.OK, person);
        }

So, that works.
Next time, let's consume this WebApi with Angularjs.

And here's all the code: here

I have changed 'Person' to 'Contact' in the sourcecode


Back to basics: db4o and ASP.NET MVC 3

Let's write an app with Db4o and ASP.NET MVC again! Check out this post first.

We've kept it simple & stupid: a model with two entities and a one-to-many relationship. It should set a base for most apps though:

A little background: in a data centre there are serverracks, with blade enclosures or blade chassis. In these enclosures, you can put servers. So, bladeservers go into one blade chassis. Here is the typical one to many relationship!

This is how I set up the solution in Visual Studio:

  • Core contains the business entities
  • Tasks is a console app to get things done quick and dirty
  • Test is for the Unit tests
  • Web is the ASP.NET MVC3 application (Empty) with Razor

So, just create a new class in Core and make it look like this:

Now go to the Db4o website quickly to grab db4o for .NET 4.0, version 8.0.160.14822 MSI. You may have to register first. Install the software.

Now open (add to the solution if you did not yet do so) the Web application and add some references:

I created the following folder structure:

Let's first create the interface for the Unit of Work:

And since we'll be using Db4o for our objectpersistence, let's create a Db4oSession, that derives from ISession.

Next, we need to set up the mechanism that handles the connection to the database for us. This is the SessionFactory:

Now, we are ready to write our first tests:

I can run them successfully in Nunit, which is awesome.

And yes, this all is based on the weblog of my hero Rob Conery. I am so sorry.

Well, we're almost there. We can actually write our controller methods now. Let's add a BladeChassisController and add the Index method:

public ActionResult Index()
        {
            var chassis = SessionFactory.Current.All<BladeChassis>();
            return View(chassis);
            
        }

And this would be our Edit method (that retrieves an instance of the bladechassis to edit):

public ActionResult Edit(int id)
        {
            string cid = id.ToString();
            var chassis = SessionFactory.Current.Single<BladeChassis>(x => x.ChassisID == cid);
            return View(chassis);
        }

And this is the actual altering the 'record' in the 'database':

[HttpPost]
        public ActionResult Edit(int id, FormCollection values)
        {
            try
            {
                // TODO: Add update logic here
                string cid = id.ToString();
                var c = SessionFactory.Current.Single<BladeChassis>(x => x.ChassisID == cid);
                
                UpdateModel(c);
                SessionFactory.Current.Save(c);
                SessionFactory.Current.CommitChanges();
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

And here is the delete method:

public ActionResult Delete(int id)
        {
            try
            {
                string cid = id.ToString();
                var chassis = SessionFactory.Current.Single<BladeChassis>(x => x.ChassisID == cid);
                SessionFactory.Current.Delete(chassis);
                return RedirectToAction("Index");
            }
            catch
            {
                return View("Index");
            }
        }

It's insanely simple. (Until you need to fill a DropDownList, but that's a separate article).

You can download the example here.
Don't forget to run the Console App in Tasks first, because it adds some data to the app.


NoSQL: Eloquera and ASP.NET MVC 3 (and Ninject)

I thought today I'd give Eloquera a swing, just to do something fun and new before starting the other obligations of the day. Eloquera is another objected oriented database, like Db4o or MongoDb. The difference is that Eloquera is natively .NET and it's free whereas db4o is not. But I honestly do not prefer the one above the other. I'm just trying things out.

I wrote a quick web application as a POC.

First, download Eloquera from here. I took the x64 .NET 4.0 version and installed it..
I edited the C:\Program Files\Eloquera\Eloquera Server 3.0\Eloquera.config file so that the Eloquera files are in c:\temp\db by adding DatabasePath="c:\temp\db":

  <Server ServerPort="43962" 
            DatabasePath="c:\temp\db"
            Trace="true" 
            InMemoryAllowed="true"
            Secure="true" 
            AllowUsers="" 
            AllowGroups="Everyone" />
    <SmartRuntime Smart="true" />

Oh and don't forget to take a look in the Samples directory in the program folder.

Then I created an new ASP.NET MVC 3 application and edited the Global.asax.cs. Here is the relevant portion:

Here are the gotcha's:

  • The OpenSession() method opens the database and if it doesn't exist, a new one is created with some dummy data.
  • I use the session-per-web request pattern (the lifetime of a session is the same as a web request). You can see that here in the complete Global.asax.cs.
  • I do not have to deal with Transactions with Eloquera.
  • I have to register types explicitly, else the Views won't recognize them: db.RegisterType(typeof(iSay.Story));

And then I only have to get the current session in my Repositories with (private DB db = MvcApplication.db;) and I'm good to go just like any other app!

using Eloquera.Client;

namespace iSay.Infrastructure
{
    public class StoryRepository : IStoryRepository
    {
      private DB db = MvcApplication.db;
        public IEnumerable<Story> getStories()
        {
           return db.ExecuteQuery("SELECT Story").OfType<Story>();
        }

        public void Add(Story s)
        {
            db.Store(s);
        }

        public int getNumberOfComments(Story s)
        {
            var comments = s.Comments.Count();
            return comments;
        }
    }
}

The controller (I used Ninject again, as you can see I injected the controller with IStoryRepository):

using iSay.Infrastructure;

namespace iSay.Controllers
{
    public class HomeController : Controller
    {
        private IStoryRepository _repo;

        public HomeController(IStoryRepository repo)
        {
            _repo = repo;
        }

        public ActionResult Index()
        {
            var stories = _repo.getStories();
            return View(stories);
        }

    }
}

Hmm, that's almost embarrassing, as easy as this is.

You can view the source code here. Maybe I'll spice it up later but I have to go now.


ASP.NET MVC and MongoDb Part 2

In the former blogpost we've explored MongoDb and we've created a very basic MVC application with the norm.dll. We created a User and a Bug class, but we've only implemented some CR (and not UD) for the User class.
In this post I will explore how to deal with a one-to-many relationship in a document based database, i.e. a non relational database.
classdiagram

One user can submit more bugs, so there is a one to many relationship between the user and the bugs. But how to implement that in an app where there is no relational database and where there are no constraints?

This were the ViewModel pattern comes in.

Below I created a new class, the BugViewModel class, which is a combination of attributes or fields from the Bug and the User class:

namespace BugBase.ViewModels
{
    public class BugViewModel
    {
        public ObjectId Id { get; set; }
        public ObjectId UserId { get; set; }
        public string ShortDescription { get; set; }
        public string LongDescription { get; set; }
        public DateTime? Date { get; set; }
        public bool Status { get; set; }
        public string Email { get; set; }
        public string UserName { get; set; }
    }
}

So, that's great. Thank you Framework! But however do I map those attributes to the User and Bug classes?
There is AutoMapper, an object to object mapper by Jimmy Bogard, available here. But I think Automapper is a bit complex to use. For simple scenario's, like BugBase, there is a solution in the ASP.NET MVC futures assembly. This assembly provides a static class, the ModelCopier, that can also use for copying values between View Model objects and Domain model objects. It's available here at Codeplex. The dll is called Microsoft.Web.Mvc.dll. Add a reference to it in BugBase and you're good to go.

The controller create method, would look like this:

[HttpPost]
 public ActionResult Create(BugViewModel bugviewmodel)
   {
       var bug = new Bug();
       ModelCopier.CopyModel(bugviewmodel, bug);

       using (var session = new MongoSession())
        {
         string username = bugviewmodel.UserName;
            var user = session.users
              .Where(u => u.UserName == username)
                  .FirstOrDefault();

                bug.User = user;
                session.Save(bug);                
         }
      return RedirectToAction("Index");
      }
 }

You see how easy it is to add a user to a bug using the ViewModel Pattern and copy the viewmodel to the original domain class.

Next time we'll spice up the userinterface and we'll add some jQuery and Ajax.


(Another) ASP.NET MVC 2.0 app with MongoDb Part 1

I have been fiddling around with Db4o and well.. I did not finish my app. Which probably means that it is time to try out yet another document based database. So. Let's cover MongoDb this time.

I will now create a webapplication where users can submit bugs for a certain software project. Let's call it BugBase.

The first step is to create the folders c:\data and c:\data\db. These are the default folders that you can override if you wish. The next step is to download the Mongo binaries and extract them in c:\data\db.

As with many nosql databases they're obscenely trivial to install. Click on mongod.exe in the bin folder and the Mongo server is running:

mongodb

Let's see if this works. Let's create a bug record for "unable to save" in a database.

C:\data\db\bin>mongo
MongoDB shell version: 1.4.2
url: test
connecting to: test
type "exit" to exit
type "help" for help
> b = { description : "unable to save" };
{ "description" : "unable to save" }
> b = { bugtext : "unable to save the records"};
{ "bugtext" : "unable to save the records" }
> db.bugbase.save(b);
> db.bugbase.find();
{ "_id" : ObjectId("4c03a7fa0e6c000000004226"), "bugtext" : "unable to save the
records" }
>

mongocli

Apparently it does work 😉
I inserted a record in a document (ie table) and Mongo created a unique identifier for me. Cool.

Put Mongo in an ASP.NET MVC 2 app

First step is to create an MVC2 app in Visual Studio 2010 and get rid of all the standard stuff from the template.

Did somebody actually write a MongoDb to Linq provider? But yes of course! My hero Rob Conery did. And Andrew Theken took it further and hosts the project on Github.

What a surprise, only yesterday Andrew uploaded a new version. Wherever would I be without the efforts of these brilliant people? Download the latest Norm project (should I use Github) and compile it in Visual Studio. Grab the norm.dll from the bin folder and add a reference to it in the BugBase project.

Next I need an example as of how to use this dll. At Codeplex Shiju Varghese wrote an example application, which I will use as a reference. But you don't need to check out all these examples. It's just to give the credits to the people that made all this possible.

For BugBase we need at least 2 classes. Bug and User. Create them in the Models folder.

 public class User
    {
        [MongoIdentifier]
        public ObjectId Id { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public List Bugs { get; set; }

        public User() {
            Bugs = new List();
        }
    }
public class Bug
    {
        [MongoIdentifier]
        public ObjectId Id { get; set; }
        public string ShortDescription { get; set; }
        public string LongDescription { get; set; }
        public DateTime? Date { get; set; }
        public bool Status { get; set; }
        public User User { get; set; } 
    }

Now, let's add a folder called Infrastructure to put all the data layer stuff in. Create a new class called MongoSession.cs.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Norm;
using Norm.Collections;
using Norm.Linq;
using Norm.Responses;
using BugBase.Models;

namespace BugBase.Infrastructure
{
    internal class MongoSession : IDisposable
    {
        private readonly MongoQueryProvider provider;

        public MongoSession()
        {
            var mongo = new Mongo("BugBase", "localhost", "27017", "");
            this.provider = new MongoQueryProvider(mongo);
        }

        public IQueryable Bugs
        {
            get { return new MongoQuery(this.provider); }
        }
        public IQueryable users
        {
            get { return new MongoQuery(this.provider); }
        }
        public MongoQueryProvider Provider
        {
            get { return this.provider; }
        }

        public void Add(T item) where T : class, new()
        {
            this.provider.DB.GetCollection().Insert(item);
        }

        public void Dispose()
        {
            this.provider.Server.Dispose(); 
        }
        public void Delete(T item) where T : class, new()
        {
            this.provider.DB.GetCollection().Delete(item);
        }

        public void Drop()
        {
            this.provider.DB.DropCollection(typeof(T).Name);
        }

        public void Save(T item) where T : class,new()
        {
            this.provider.DB.GetCollection().Save(item);            
        }
    }    
  }

We've got the models in place and the datalayer, so let's create a UserController.

usercontroller

Let's create a view.

usercreateview

Create a strongly typed view with the BugBase.Models.User View Data Class and Create as View Content.

Now let's add the controllermethods to create a user and list them:

 public ActionResult Index()
        {
            using (var session = new MongoSession())
            {
                var userlist = session.users.AsEnumerable();
                return View(userlist);
            }
        }
 [HttpPost]
        public ActionResult Create(User user)
        {
            using (var session = new MongoSession())
            {
                session.Save(user);
            }
            return new RedirectResult("/User");
        }

Compile the project and behold the result:

usercreate

And the list: (OK, never mind the poor security of this app)

userlist

Next time let's implement the bugs. You can download the very beta beta beta BugBase App here.