My Adventures in Coding

March 27, 2013

C# – Using Unity for Dependency Injection in an ASP.NET MVC 4 Web API

Filed under: .NET,c#,MVC,REST — Brian @ 11:27 pm
Tags: , , ,

When I created my first REST API since I started working with MVC 4 Web API, immediately I wanted to figure out how to handle dependency injection. When I had previously worked in Java I used Spring, in Scala I used Google Guice, and so now I was on the hunt for another dependency injection tool. There are several options out there, such as Spring .NET and also Ninject, however for now we decided to go with Unity because of it’s simple setup and maturity.

With MVC 4 Web API the application creates an instance of the controller class whenever a REST call is made. So for example if you have the REST endpoint /cars it will create an instance of the controller CarsController to service the request. Now, this all works fine until you change the constructor on CarsController to take a parameter. Once you do this, you will need a dependency injection framework to handle knowing how to resolve the dependencies for CarsController when one is being created. So let’s use this as our example.

Note: For this example I am using:
Visual Studio 2012 Express Web and version 2.1.505.2 of the Unity NuGet package.

Now, in Visual Studio 2012 NuGet is built right in, so no need to install the NuGet Plugin anymore (Woohoo!)

Step 1 – Create a new Web API Project

Create a new Web API project in Visual Studio:

  • File -> New Project
  • Installed -> Templates -> Visual C# -> Web
  • Give the project the name: UnityExample
  • Click “OK”
  • Select Project Template -> Web API
  • Click “OK”

That’s all! Now you have a new Web API project called UnityExample.

Step 2 – Install Unity NuGet Package

For installing NuGet packages you can use either the GUI tool or the console.

To use the Package Manager Console tool:

  • To open the console: Tools -> Library Package Manager -> Package Manager Console
  • Now at the console prompt enter the command: Install-Package Unity

Now, if you prefer to use the GUI tool:

  • In Solution Explorer, right click on the solution and select Manage NuGet Packages for Solution
  • Ensure Online is selected, then in the search box type Unity
  • The Unity package will be displayed at the top of the list then click Install

Step 3 – Create an IOC (Inversion of Control) Container

You will need to create an IOC container that impelements IDependencyResolver. I did not write my own, I got this code from here.

using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;
using Microsoft.Practices.Unity;

namespace UnityExample
{
    // This code is from:
    // http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver
    // The website also has a detailed explanation of how to setup dependency injection

    public class ScopeContainer : IDependencyScope
    {
        protected IUnityContainer container;

        public ScopeContainer(IUnityContainer container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            this.container = container;
        }

        public object GetService(Type serviceType)
        {
            if (container.IsRegistered(serviceType))
            {
                return container.Resolve(serviceType);
            }
            else
            {
                return null;
            }
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            if (container.IsRegistered(serviceType))
            {
                return container.ResolveAll(serviceType);
            }
            else
            {
                return new List<object>();
            }
        }

        public void Dispose()
        {
            container.Dispose();
        }
    }

    class IoCContainer : ScopeContainer, IDependencyResolver
    {
        public IoCContainer(IUnityContainer container)
            : base(container)
        {
        }

        public IDependencyScope BeginScope()
        {
            var child = container.CreateChildContainer();
            return new ScopeContainer(child);
        }
    }
}

Step 4 – Create a new class called NameService.cs

The following class with be the dependency that we will inject into our new controller.

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

namespace UnityExample
{
    public class NameService
    {
        private string _myName;

        public NameService(string myName)
        {
            _myName = myName;
        }

        public string GetMyName()
        {
            return string.Format("My name is: {0}", _myName);
        }
    }
}

Step 5 – Create a new Controller called NameController which requires NameService as a constructor parameter

To create the new controller NameController:

  • Right click on the Controllers folder and select Add -> Controller
  • Enter Controller name: NameController
  • From the Template drop-down select Empty API controller

Now enter the following code in your new NameController class:

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

namespace UnityExample.Controllers
{
    public class NameController : ApiController
    {
        private NameService _nameService;

        public NameController(NameService nameService)
        {
            _nameService = nameService;
        }

        public string Get()
        {
            return _nameService.GetMyName();
        }
    }
}

Step 6 – Setup Dependency Injection with Unity in Global.asax.cs

Now the final step is to create an instance of NameService and tell Unity to use that instance anytime an instance of NameController is created.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

// Add usings for Unity and Controllers
using Microsoft.Practices.Unity;
using UnityExample.Controllers;

namespace UnityExample
{
    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            // Create a new Unity dependency injection container
            var unity = new UnityContainer();

            // Register the Controllers that should be injectable
            unity.RegisterType<HomeController>();
            unity.RegisterType<NameController>();

            // Register instances to be used when resolving constructor parameter dependencies
            unity.RegisterInstance(new NameService("It Worked!!!"));

            // Finally, override the default dependency resolver with Unity
            GlobalConfiguration.Configuration.DependencyResolver = new IoCContainer(unity);
        }
    }
}

Step 7 – Now let’s run the app and see that it worked!

Now run the app: Debug -> Start Without Debugging or (Ctrl F5).

When a browser opens, you will see the usual default home page for a .Net MVC 4 Web API application.

Now add the following to your url: /api/name. For example: http://localhost:62283/api/name.

Note: Remember the default path for all ApiControllers in Web API always starts with /api.

You should see the following output:

<string>My name is: It Worked!!!</string>

That is all!

Now that you have a working example, I recommend you read more about how it works in the following article:

Using the Web API Dependency Resolver

July 5, 2012

C# – Logging Exceptions with Elmah in an MVC 4 Web API Application

Filed under: .NET,c#,MVC — Brian @ 11:08 pm
Tags: , ,

Recently, after having been away from the .NET world for several years, I have started on a new project where we are building REST APIs using MVC 4. One of the first things we wanted to find out how to do was have all exceptions written to a database, as well as have a web interface from which to view exception details. Fortunately there is a very nice open source project available called Elmah.

When I created my first MVC 4 Web API application using Elmah, I was very rusty with .NET so getting Elmah setup and working took me a little longer than expected. Part of the reason was because the setup required piecing together information from multiple sources, since things have changed a bit in MVC 4. So here is a very simple quick start tutortial to help you get up and running with Elmah. If you would like to learn more about Elmah, the following article gives a good overview: Logging Error Details with ELMAH (C#).

NOTE: If you are using NuGet, you can use the Elmah.MVC NuGet Package to install Elmah, which works great. However, if you are not using NuGet, the following instructions will walk you through the setup.

1. Create a new MVC 4 Web API Project

The following article is useful, if you have never created an MVC 4 Web API application before:
ASP.NET WebAPI: Getting Started with MVC4 and WebAPI

2. Download the latest version of Elmah

You can obtain the latest version of Elmah here. At the time of this post, I am using version 1.2 Service Pack 2.

Unpack the zip file ELMAH-1.2-sp2-bin-x64.zip and add the following dll to your project as a reference:
…\ELMAH-1.2-sp2-bin-x64\bin\net-2.0\Release\Elmah.dll

3. Setup Elmah in your Web.config file

To the configSections part of your Web.config, add an Elmah sectionGroup:

<configSections>
<sectionGroup name="elmah">
      <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah"/>
      <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
      <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
      <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah"/>
    </sectionGroup>
…
</configSections>

To log to a Microsoft SQL Server database (In our case we are using SQL Server 2005), add a connection string for Elmah filling in your database server name and the name of your exceptions database:

<connectionStrings>
        <add name="elmah-sql" connectionString="Data Source=MY_DB_HOST;Initial Catalog=MY_EXCEPTIONS_DB_NAME;Integrated Security=SSPI;Connection Timeout=60;Min Pool Size=2;Max Pool Size=20;" providerName="System.Data.SqlClient" />
  </connectionStrings>

Inside the configuration tag add an Elmah section setting the “applicationName” to be some unique string to identify your application:

<configuration>
    <elmah>
        <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="elmah-sql" applicationName="SETMYAPPLICATIONNAME"></errorLog>
        <security allowRemoteAccess="1" />
    </elmah>
    ...
</configuration>

Inside the system.web tag add:

<system.web>
    <httpModules>
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
    </httpModules>
    <httpHandlers>
      <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
    </httpHandlers>
    ...
</system.web>

In the system.webServer tag add:

<system.webServer>
    <handlers>
      <add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
    </handlers>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true">
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
    </modules>
    ...
</system.webServer>

4. Run the Elmah SQL Server database setup script on your Exceptions database

You need to apply the script that creates the Elmah table where exception information will be logged, as well as adds the stored procedure required by the web interface to read exception messages. The script is located in the zip file you downloaded, located at:
…\ELMAH-1.2-sp2-bin-x64\db\SQLServer.sql.

5. Create a custom ExceptionFilterAttribute class

Even though, up to this point we have completed all the required setup for Elmah, it will still not work in our MVC 4 Web API project. To log exceptions to Elmah you must create a custom ExceptionFilterAttribute class and use that to call Elmah when an exception occurs.

public class ElmahErrorAttribute : System.Web.Http.Filters.ExceptionFilterAttribute
{
    public override void OnException(
         System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
    {
        if (actionExecutedContext.Exception != null)
            Elmah.ErrorSignal.FromCurrentContext().Raise(actionExecutedContext.Exception);
        base.OnException(actionExecutedContext);
    }
}

6. Register the custom ExceptionFilterAttribute class in your global.ascx.cs file

Finally, you must register your custom ExceptionFilterAttribute class on startup.

protected void Application_Start()
{
    GlobalConfiguration.Configuration.Filters.Add(
        new ElmahErrorAttribute()
    );
    ….
}

That’s it! Now you should be able to run your web app and go to the page:

http://localhost:SOMEPORT/elmah.axd

June 19, 2012

C# – Supporting text/plain in an MVC 4 Web API application

Filed under: .NET,c#,MVC — Brian @ 10:50 pm
Tags: , , , , , ,

If you have just created a brand new MVC 4 Web API application and when posting data with content-type: text/plain to a method in your ApiController that takes a string, you notice that the value in the string is null, this is caused by your application not having support for the media type “text/plain”.

No worries, after some digging I figured out how to get this to work.

Create the following custom MediaTypeFormatter in your application

using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace WebApiMvc4Example
{
    public class TextMediaTypeFormatter : MediaTypeFormatter
    {
        public TextMediaTypeFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));
        }

        public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
        {
            var taskCompletionSource = new TaskCompletionSource<object>();
            try
            {
                var memoryStream = new MemoryStream();
                readStream.CopyTo(memoryStream);
                var s = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
                taskCompletionSource.SetResult(s);
            }
            catch (Exception e)
            {
                taskCompletionSource.SetException(e);
            }
            return taskCompletionSource.Task;
        }

        public override bool CanReadType(Type type)
        {
            return type == typeof(string);
        }

        public override bool CanWriteType(Type type)
        {
            return false;
        }
    }
}

Add the custom MediaTypeFormatter into the Application_Start method in your Global.asax.cs file

using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace WebApiMvc4Example
{
    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            // Add a reference here to the new MediaTypeFormatter that adds text/plain support
            GlobalConfiguration.Configuration.Formatters.Insert(0, new TextMediaTypeFormatter());
        }
    }
}

Now add the “FromBody” tag to your POST method that takes in a string in your ApiController

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

namespace WebApiMvc4Example.Controllers
{
    public class ValuesController : ApiController
    {
        // GET api/values
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        // Add the "FromBody" tag
        public void Post([FromBody] string value)
        {
            System.Diagnostics.Debug.WriteLine("******Woohoo: " + value);
        }

        // PUT api/values
        public void Put(string value)
        {
        }

        // DELETE api/values/5
        public void Delete(int id)
        {
        }
    }
}

That is all. So now if you start up your application:
POST to http://localhost:MYPORT/api/values with headers “content-type: text/plain” and with body “SOMETEXT” it will work just fine now.

I hope this helps!

Blog at WordPress.com.