Setting a different Web.config for every publish environment (Config Transformation)

First of all, since a VS project comes with just 2 build configurations (Debug and Release), we need to create a new build configuration for Staging. In this way we’ll be able to have a Web.config transformation for it as well.

We can add the new build configuration from the Configuration Manager:

Now that we have all the build configurations we need we can create a config transformation for our new Staging build configuration (we should already have the one for Debug and Release) by right-clicking on our Web.config and selecting “Add Config Transform”. A new Web.Staging.config file will be added under the Web.config in the solution.


Working with Config Transformation files

We can use the config transformation files to specify transformations to apply to the original Web.config in order to obtain any configuration-related Web.config. Since the original Web.config is often related to a Development environment we normally don’t have any transformation to apply for the Debug build configuration (we just use the original Web.config). So what we basically do is to define transformations for the Staging and Release build configurations by replacing any configuration key that need to be different between the environments.


Updating a Connection String

A thing that is often useful to change between different environments is the value of connection strings, to be able to connect to a different DB based on the environment we are publishing to. Here is an example configuration in our original Web.config:

<connectionStrings>
  <add name="ConString" connectionString="myDebugCS" />
</connectionStrings>

And here is what we need to write in our Web.Staging.config transformation file to change its value for our Staging environment:

<connectionStrings>
  <add name="ConString" connectionString="MyConStr"
        xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>

What we are doing with the new “xdt” attributes is to tell that we want new attributes values for the item who match the “name” attribute.
As result when we’ll publish under Staging build configuration our “connectionString” property for the “ConString” connection string will be replaced with the “MyStagingCS” value.


Updating an AppSetting configuration

<add key="MyConfigurationKey" value="MyConfigurationValue" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"></add>

Adding an AppSetting configuration

<add key="MyConfigurationKey" value="MyConfigurationValue" xdt:Transform="Insert"></add>

Removing an AppSetting configuration

<add key="MyConfigurationKey" xdt:Transform="Remove" xdt:Locator="Match(key)"></add>

Replacing a node with all its subnodes

In this case we want to replace the whole node and its content (so the inner “network” node as well) for the smtp configuration whose “from” attribute is “target-email@my-company.com”.

<smtp deliveryMethod="Network" from="target-email@my-company.com" xdt:Transform="Replace" xdt:Locator="Match(from)">
  <network host="my-company.host.com" port="25"></network>
</smtp>

Replacing a node based on its subnodes

This is something that can happen if we have to replace something about assembly bindings, which is defined by a list of nodes like this:

<dependentAssembly>
  <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
  <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>

Let’s imagine that we want to replace the “dependantAssembly” configuration node for the “System.Web.Helpers” assembly. Unfortunately
this information is written inside the “assemblyIdentity” inner node, so we have to specify a more complex rule:

<dependentAssembly xdt:Transform="Replace"
                   xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Helpers')">
  <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"></assemblyIdentity>
  <bindingRedirect newVersion="3.0.0.0" oldVersion="0.0.0.0-3.0.0.0"></bindingRedirect>
</dependentAssembly>

Integrating MVC Web API with Castle.Windsor

Unfortunately the mechanism we use to integrate the normal MVC controllers with Castle.Windsor doesn’t work when we have to integrate Web API controllers. In order to integrate these kind of controllers as well we need to use another technique. First of all we need to create a new Dependency Resolver and a new Dependency Scope (e.g. within the usual “Infrastructure” folder):

public class CastleDependencyResolver : IDependencyResolver
{
    private readonly IKernel _kernel;
 
    public CastleDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }
 
    public IDependencyScope BeginScope()
    {
        return new CastleDependencyScope(_kernel);
    }
 
    public object GetService(Type type)
    {
        return _kernel.HasComponent(type) ? _kernel.Resolve(type) : null;
    }
 
    public IEnumerable<object> GetServices(Type type)
    {
        return _kernel.ResolveAll(type).Cast<object>();
    }
 
    public void Dispose()
    {
    }
}

public class CastleDependencyScope : IDependencyScope
{
    private readonly IKernel _kernel;
    private readonly IDisposable _disposable;
 
    public CastleDependencyScope(IKernel kernel)
    {
        _kernel = kernel;
        _disposable = kernel.BeginScope();
    }
 
    public object GetService(Type type)
    {
        return _kernel.HasComponent(type) ? _kernel.Resolve(type) : null;
    }
 
    public IEnumerable<object> GetServices(Type type)
    {
        return _kernel.ResolveAll(type).Cast<object>();
    }
 
    public void Dispose()
    {
        _disposable.Dispose();
    }
}

Now we have to tell MVC Framework to use our DependencyResolver instead of the default one. To do this we have to add some code (as usual) to the Application_Start() method of the global.asax file. Here is how it appears with both the normal MVC and the Web API controllers configured to be integrated with Castle.Windsor:

void Application_Start(object sender, EventArgs e)
{
    AreaRegistration.RegisterAllAreas();
    GlobalConfiguration.Configure(WebApiConfig.Register);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
 
    //Creates Castle Container
    var container = new WindsorContainer();
    container.Install(new CastleInstaller());
 
    //Creates Castle Controller Factory (MVC)
    var castleControllerFactory = new CastleControllerFactory(container);
    ControllerBuilder.Current.SetControllerFactory(castleControllerFactory);
 
    //Creates Castle Controller Factory (Web API)
    var castleDependenctResolver = new CastleDependencyResolver(container.Kernel);
    GlobalConfiguration.Configuration.DependencyResolver = castleDependenctResolver;
}

Adding all the controllers to the installer

As usual we must register all the Web API controllers (as we did with the normal MVC controllers). Here is how to register both the normal MVC and the Web API controllers with few lines of code:

//Register all the controllers
//in the current executing assembly
container.Register(Classes.FromThisAssembly().BasedOn<Controller>().LifestylePerWebRequest());
container.Register(Classes.FromThisAssembly().BasedOn<ApiController>().LifestyleScoped());

WebAPI REST Service (MVC Framework)

With the Web API I can easily create a REST service. Theoretically a REST service uses 4 different HTTP verbs to perform the basic CRUD operations on a particular entity. These verbs are:

GET This verb is used to read data
PUT This verb is most often used to update an existing entity
POST This verb is most often used to create a new entity
DELETE This verb is used to delete an entity

In practice what is often done (even why not all browsers support all the methods) is to use the GET verb to read/delete and the POST verb to create/update (we use the POST verb every time we have to send the whole object and not just the id).

Here is an example of a REST service made using a Web API controller:

[RoutePrefix("api/post")]
public class PostController : ApiController
{
    [HttpGet]
    [Route("get")]
    public List<PostModel> Get()
    {
        return new List<PostModel>()
        {
            new PostModel()
            {
                Title = "Post 1",
                Content = "Post 1 Content",
                DateCreated = new DateTime(2015,01,12)
            },
            new PostModel()
            {
                Title = "Post 2",
                Content = "Post 2 Content",
                DateCreated = new DateTime(2015,01,13)
            },
            new PostModel()
            {
                Title = "Post 3",
                Content = "Post 3 Content",
                DateCreated = new DateTime(2015,01,14)
            }
        };
    }
 
    [HttpPost]
    [Route("create")]
    public bool Create([FromBody]PostModel model)
    {
        //Save PostModel to DB
        return true;
    }
}

It can be easily referred by the client using the get()/post() JQuery methods, to invoke the service with the proper HTTP verbs:

<button id="getPost">GET</button>
<button id="createPost">POST</button>

@section scripts
{
    <script>
        $("#getPost").bind("click", function () {
            $.get("/api/post/get", function (data) {
                alert(data);
            });
        });
 
        $("#createPost").bind("click", function () {
            $.post("/api/post/create", {
                title: "Post 4",
                content: "post 4 content",
                dateCreated: "2014/01/16"
            },
            function (data) {
                alert(data);
            });
        });
    </script>
}

WebAPI 2 Controllers (MVC Framework)

Web APIs are a way to use controllers to return raw data instead of html. Even thought is possible to return JSon from a normal controller’s action, a Web Api allow us a more data oriented environment, with many features which allow us a more powerful approach on that direction.

To add a new Web API Controller to an existent MVC Web Application (is possible as well to add a dedicated Web API project to our solution) we can right-click on our Controllers folder (or on the folter we want to use for our Web API controllers) and the select Add -> Controller. From the Controller selection form we can choose to add a new “Web API 2 Controller Empty”.

Doing this some new references and files will be added to the solution, to allow us to work with Web APIs. In particular we will have a new WebApiConfig.cs file, that is for the WebAPIs what something similar at what the RouteConfig.cs is for the normal controllers. Here is how it looks like:

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

To be sure that everything works we have to ensure that the Register() method is effectively called in the Global.asax file. It’s important that the method is called just after the RegisterAllAreas() method, otherwise we can have some issue with the routing configuration. Here is a example of how the Global.asax should look like:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    GlobalConfiguration.Configure(WebApiConfig.Register);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

As we can see we have a call to the MapHttpAttributeRoutes() method, to have automatically enabled the route attributes (as the MapMvcAttibuteRoutes() method does for the normal controllers). The we have the default routing configuration for our Web API controllers. Even though a configuration is provided is highly recommended, especially when parameters are provided, to use the route attributes to specify every route.

Differently from the normal controllers, which can return JSon data by returning the result of the Json() method as action, in this case we are just returning the object with the result of our method. Here is an example:

[Route("api/forumApi/getIntListWithCount/{count}")]
public List<int> GetIntListWithCount(int count)
{
    var list = new List<int>();
    for (var n = 0; n < count; n++)
    {
        list.Add(n);
    }
    return list;
}

Managing the output format

If we try to invoke our Web API we’ll discover that probably our list will be returned in XML format. It should be better to have it on JSon format. In reality things are a little more complicated: Web APIs implements a negotiation mechanism which return the result object in different formats based on the request. Indeed we can invoke our method from the client side to have the result as JSon or as XML:

<script>
    $.ajax({
        dataType: "json",
        url: "/api/forumApi/getIntListWithCount/20",
        success: function (data) {
 
            //Data as JSon
            debugger;
        }
    });
    $.ajax({
        dataType: "xml",
        url: "/api/forumApi/getIntListWithCount/20",
        success: function (data) {
 
            //Data as XML
            debugger;
        }
    });
</script>

So the reason why, if we try to directly refer our Web API method from the browser, we’ll probably get the result with XML format, is because many browsers add the XML content format by default when asking for an html page (and of course the browser is asking for an html page by default). So how can we fix this? Fortunately we just have to add some extra configuration to our WebApiConfig.cs file:

public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();
 
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
 
    //We set JSon as default format for any text/html request
    config.Formatters.JsonFormatter.SupportedMediaTypes.Add(
        new MediaTypeHeaderValue("text/html"));
 
    //We configure a way to force the output format by adding ?type=json to
    //force the json format and by adding ?type=xml to force the XML format
    config.Formatters.JsonFormatter.MediaTypeMappings.Add(
        new QueryStringMapping("type", "json", new MediaTypeHeaderValue("application/json")));
    config.Formatters.XmlFormatter.MediaTypeMappings.Add(
        new QueryStringMapping("type", "xml", new MediaTypeHeaderValue("application/xml")));
}

Advanced routing (MVC Framework)

As we know the routing configuration of a MVC Framework application can be found within the RouteConfig.cs file. The default configuration is something like this:

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

Which tells MVC Framework that we want to map an url like “/myController/myAction” to an action named “MyAction” of a controller named “MyControllerController”. The {id} parameter allows us to to send a parameter (optional in this case), called “id”, to our action. So an action like the following one is automatically handled by the default configuration and can be reached with this url: “/myController/GetTestObjectWithId/123”.

public ActionResult GetTestObjectWithId(int id)
{
    return Json(new
    {
        Name = "Test",
        Value = "TestValue",
        Id = id
    }, JsonRequestBehavior.AllowGet);
}

Defining a custom routing

If we need a custom routing we have to setup a specific rule to tell MVC Framework how to map the action with the desired url. For example let’s say that we want to reach the following action with this url “/myController/GetTestObjectWithParameter/123”:

public ActionResult GetTestObjectWithParameter(int parameter)
{
    return Json(new
    {
        Name = "Test",
        Value = "TestValue",
        Parameter = parameter
    }, JsonRequestBehavior.AllowGet);
}

This action looks very similar to the previous one, apart the parameter’s name. Well, this difference is enough to require us to define a custom routing rule. Indeed the default configuration uses a parameter called “id”, so if we try to refer this action with the url “/myController/GetTestObjectWithParameter/123” MVC Framework will not be able to map the token “123” of the url to the action’s parameter because it has a different name.

Without defining a custom routing the only way to reach this action is using this url “/myController/GetTestObjectWithParameter?parameter=123”. That is not as beautiful as the previous one.

So how can we define a custom routing rule? The classic way is to add another rule within the RouteConfig.cs file. Is important to insert any custom rule before the default one, because if many rules match the same url just the first one will be considered.

routes.MapRoute(
    name: "TestGetObjectWithParameters",
    url: "test/getTestObjectWithParameter/{parameter}",
    defaults: new { controller = "Test", action = "GetTestObjectWithParameter", parameter = @"\d+" });
 
routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

With the @”\d+” configuration over the “parameter” parameter we are telling that it should fit the provided regular expression, so we want an integer parameter. Other options are available, see the documentation for a complete list.


Using the routing attibutes

From the version 5.0 of MVC Framework is possible to use another way to define custom route rules. We can use the routing attributes to associate an action with its route directly on the action’s definition, without writing anything on the RouteConfig.cs. In order to be able to take advantage of this feature we need to enable it from he RouteConfig.cs (before any other rule). This can be done using the MapMvcAttributeRoutes() method in this way:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.MapMvcAttributeRoutes();
 
    routes.MapRoute(
        name: "TestGetObjectWithParameters",
        url: "test/getTestObjectWithParameter/{parameter}",
        defaults: new { controller = "Test", action = "GetTestObjectWithParameter", parameter = @"\d+" }
    );
 
    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

After enabled this feature we can easily assign a custom route to an action:

[Route("test/getTestObjectWithParameters/{parameter1}/{parameter2}")]
public ActionResult GetTestObjectWithParameters(int parameter1, int parameter2)
{
    return Json(new
    {
        Name = "Test",
        Value = "TestValue",
        Parameter1 = parameter1,
        Parameter2 = parameter2
    }, JsonRequestBehavior.AllowGet);
}

With attributes is possible to specify many behaviors, not just at action-level, but a controller-level as well. For example we can specify the route prefix for any action of the controller or the default action name. At action-level we can define if a parameter is optional (using “?”) or other constraints like the value type. See the documentation for a complete list of options.

Return JSon from an Action (MVC Framework)

I can return the JSon of any object from a common action by using the Json() method of the Controller class.

public class TestController : Controller
{
    public ActionResult GetTestObject()
    {
        return Json(new
        {
            Name = "Test",
            Value = "TestValue"
        }, JsonRequestBehavior.AllowGet);
    }
}

The AllowGet option tell MVC Framework that we want to be able to get this JSon from a get request on this action. Without it we’ll receive a runtime error, because by default MVC Framework won’t return any JSon content for security reasons.

Creating Bundles with MVC Framework

In an MVC Framework web application I can create multiple bundles from the App_Start/BundleConfig.cs file. Within that file I can define each bundle together with its content. I can as well to specify that all the files of a particular type included in a target folder should be added to the bundle.

Here is an example on how to define a bundle which contains two well specified JS files plus all the JS files from a particular folder:

bundles.Add(new ScriptBundle("~/bundles/angularApp").Include(
            "~/app/angularApp.js",
            "~/app/controllers/*.js",
            "~/app/statesConfig.js"));

To render a bundle within a Razor view I can use the @Script.Render (because in this case we have a script bundle) instruction:

@section scripts
{
    <script src="~/Scripts/angular.min.js"></script>
    <script src="~/Scripts/angular-ui-router.min.js"></script>
    @Scripts.Render("~/bundles/angularApp")
}