@Shazwazza

Shannon Deminick's blog all about web development

Model binding with FromServices in ASP.Net 5

December 8, 2014 03:34

Here’s a new nifty feature I found in ASP.Net 5 – you can construct your model during model binding with IoC without any additional work. This is available on the dev branch on GitHub and is based on something called ServicesModelBinder. This is actually pretty cool because it means that you can have a model wired up with all of it’s dependencies based on IoC and then bound to your controller action’s parameters.

FromServices attribute

There’s a new attribute called FromServices which is what you use to enable this functionality. For example:

public async Task<ActionResult> GetProduct(
    [FromServices]ProductModel product)
{

}

What this attribute does is tell MVC to bind the model using IServiceActivatorBinderMetadata which is what the FromServices attribute implements. This in turn tells MVC to lookup the model binder that is aware of IServiceActivatorBinderMetadata which happens to be the ServicesModelBinder.

ServicesModelBinder

This model binder is pretty simple, it’s just going to resolve the model type from your IoC container. That could be pretty useful if you need to build up your model properties based on other services. I think some people might argue that this isn’t great practice because this is putting the binding logic in to the model itself instead of using a separate class to perform the binding logic. I suppose it’s up to the individual developer as to what their preference is. You can of course still create your own IModelBinder and use the ModelBinderAttribute to keep the model binding logic in the binder itself.

Incoming route values

Since the model is being created from IoC, how do you get the current route values to build up your model? To do that you’d put a constructor dependency on IContextAccessor<ActionContext>. This will give you all of the current route values, HttpContext, etc… basically everything you’d need to pull the data out of the current request to build your model.

Example

Given the above GetProduct example, the ProductModel class could look like:

public class ProductModel
{
    public ProductModel(IContextAccessor<ActionContext> action, IProductService prodService)
    {
        //TODO: Do some error checking...
        var productId = action.Value.RouteData.Values["product"];
        Value = prodService.Get(productId);
    }

    public IProduct Value { get; private set; }
}

This is pretty simple – the IProduct is looked up from the IProductService based on the incoming ‘product’ route value. Then in the controller you could just do: product.Value to get the value for IProduct.

You then need to ensure that both IProductService and ProductModel are registered as services in your container and it’s really important that the ProductModel is registered as a Transient object

ASP.Net 5 Re-learning a few things (part 2)

November 21, 2014 01:34

This is part 2 of a series of posts about some fundamental changes in ASP.Net 5 that we’ll need to re-learn (or un-learn!)

Part 1: http://shazwazza.com/post/aspnet-5-re-learning-a-few-things-part-1/

System.Web

This probably isn’t new news to most people since it’s really one of the fundamental shifts for ASP.Net 5 – There won’t be a System.Web DLL. Everything that you’ll install in your website will come as different, smaller, separate libraries. For example, if you want to serve static files, you’d reference the Microsoft.AspNet.StaticFiles package, if you want to use MVC, you’d include the Microsoft.AspNet.Mvc package.

ASP.Net 5: “consists of modular components with minimal overhead, so you retain flexibility while constructing your solutions

Web Forms

Gone! YAY! :-)

Web Forms will still be a part of .Net as part of the main framework in System.Web, just not part of ASP.Net 5.

HttpModules

An HttpModule simply doesn’t exist in Asp.Net 5, but of course there is a new/better way to achieve this functionality, it’s called Middleware. In an HttpModule, you had to execute code based on the various stages of a request, things such as AuthenticateRequest, AuthorizeRequest, PostResolveRequestCache, and other slightly confusingly named events. This is no longer the case with Middleware, things just make sense now … everything is simply a linear execution of your code. You can have multiple middleware’s defined to execute in your application and each one is registered explicitly in your Startup.cs file. As a developer, you are in full control of what get’s executed and in what order instead of not knowing which HttpModules are executing and not really in control of their order of execution. Middleware can simply modify a request and continue calling the next one in the chain, or it can just terminate the pipeline and return a result.

There’s loads of examples in the source for middleware, ranging from the static file middleware to cookie authentication middleware,  etc…

And here’s a good article that explains middeware registration and the flow of control.

HttpHandlers

HttpHandlers are also a thing of the past. All they really were was a request handler that was based on a specific request path. MVC (which now also includes WebApi) has got this covered. If you really wanted, you could create middleware for this type of functionality as well but unless you require something extraordinarily complex that MVC cannot do (and it can do a lot!), I’d recommend just sticking with MVC.

ClientDependency 1.8 released

July 7, 2014 08:02

It’s taken me forever to get this release out purely due to not having enough time, but here it finally is. This update now multi-targets framework versions:

  • Core project now targets both .Net 4 and 4.5
  • MVC project is now targets both .Net 4 and 4.5 for MVC 4 and .Net 4.5 for MVC 5

There are also a couple of minor bug fixes:

The update to the CDF .Less project is the update to use the latest .Less 1.4.0.0 version.

To install the CDF core:

PM> Install-Package ClientDependency

To install CDF for MVC (less than v5):

PM> Install-Package ClientDependency-MVC

If you are using MVC 5 then you’ll need to use the MVC 5 specific version:

PM> Install-Package ClientDependency-MVC5

To install the .Less update:

PM> Install-Package ClientDependency-Less

Remember CDF also supports TypeScript, CoffeeScript and SASS!

PM> Install-Package ClientDependency-TypeScript

PM> Install-Package ClientDependency-CoffeeScript

PM> Install-Package ClientDependency-SASS

Custom MVC routes within the Umbraco pipeline

May 24, 2014 02:03

A while ago I wrote a post on how to do custom MVC routing in Umbraco, though the end result wasn’t quite ideal. There were a few tricks required and It wasn’t perfect since there were problems with rendering macros on the resulting view, etc… This was due to not having a PublishedContentRequest object assigned to the context. So then we went ahead and created a new attribute to assign to your MVC action to resolve this: [EnsurePublishedContentRequestAttribute]

Like the last post, you can read a lot about all of this in this Our thread. With the [EnsurePublishedContentRequestAttribute] attribute you could now assign any IPublishedContent instance to a PublishedContentRequest and be sure that it was assigned to the UmbracoContext. But this still isn’t the most ideal way to go about specifying MVC routes to work within the Umbraco pipeline… so I’ve created the following implementation which works quite well.

Background

A little bit of background in to custom MVC routes and Umbraco… The reason why it is not terribly straight forward to create a custom route and have it assigned to an Umbraco node is because the node doesn’t exist at your custom route’s location.

For example, if we have this route:

//Create a custom route
RouteTable.Routes.MapRoute(
    "test",
    "Products/{action}/{sku}",
    new
        {
            controller = "MyProduct", 
            action = "Product", 
            sku = UrlParameter.Optional
        });

Umbraco by default would have no idea what node (IPublishedContent) would be assigned to this. The way Umbraco relates a URL to an IPublishedContent instance is by a list of IContentFinder’s. A very easy way to relate a custom URL to an IPublishedContent instance is to create your own IContentFinder. Combine that with route hijacking and in many cases this would probably be enough for your custom routing needs. However, it does not solve how you would wire up custom route parameters to your controller like how MVC normally works. Like in the above routing example, you’d want to have the ‘sku’ parameter value wired up to your Action parameter.

The above route can work and be integrated into Umbraco by following some aspects of my previous blog post and use the [EnsurePublishedContentRequestAttribute], but we can make it easier…

Creating routes

The simplest way to demonstrate this new way to create MVC routes in Umbraco is to just show you an example, so here it is:

//custom route
routes.MapUmbracoRoute(
    "test",
    "Products/{action}/{sku}",
    new
    {
        controller = "MyProduct",
        sku = UrlParameter.Optional
    },
    new ProductsRouteHandler(_productsNodeId));

This is using a new extension method: MapUmbracoRoute which takes in the normal routing parameters (you can also include constraints, namespaces, etc….) but also takes in an instance of UmbracoVirtualNodeRouteHandler.

The instance of UmbracoVirtualNodeRouteHandler is responsible for associating an IPublishedContent with this route. It has one abstract method which must be implemented:

IPublishedContent FindContent(RequestContext requestContext, UmbracoContext umbracoContext)

It has another virtual method that can be overridden which will allow you to manipulate the PublishedContentRequest however you’d like:

PreparePublishedContentRequest(PublishedContentRequest publishedContentRequest)

So how do you find content to associate with the route? Well that’s up to you, one way (as seen above) would be to specify a node Id. In the example my ProductsRouteHandler is inheriting from UmbracoVirtualNodeByIdRouteHandler which has an abstract method:

IPublishedContent FindContent(RequestContext requestContext, UmbracoContext umbracoContext, 
    IPublishedContent baseContent);

So based on all this information provided in these methods, you can associate whatever IPublishedContent item you want to the request.

Virtual content

This implementation expects any instance of IPublishedContent, so this means you can create your own virtual nodes with any custom properties you want. Generally speaking you’ll probably have a real Umbraco IPublishedContent instance as a reference point, so you could create your own virtual IPublishedContent item based on PublishedContentWrapped, pass in this real node and then just override whatever properties you want, like the page Name, etc..

Whatever instance of IPublishedContent returned here will be converted to a RenderModel for use in your controllers.

Controllers

Controllers are straight forward and work like any other routed controller except that the Action will have an instance of RenderModel mapped to it’s parameter. Example:

public class MyProductController : RenderMvcController
{
    public ActionResult Product(RenderModel model, string sku)
    {
        //in my case, the IPublishedContent attached to this
        // model will be my products node in Umbraco which i 
        // can now use to traverse to display the product list
        // or lookup the product by sku
            
        if (string.IsNullOrEmpty(sku))
        {
            //render the products list if no sku
            return RenderProductsList(model);
        }
        else
        {
            return RenderProduct(model, sku);
        }
    }
}

I have this all working well in a side project of mine at the moment. This functionality will be exposed in an upcoming Umbraco version near you  :)

It’s also worth noting that all of this was accomplished outside of the Umbraco core with the publicly available APIs that currently exist. I will admit though there were a few hacks involved which of course won’t be hacks when moved into the core ;)

Multi targeting a single .Net project to build for different framework versions

May 2, 2014 04:18

Consider this scenario:

  • I have a project that relies on ASP.Net MVC and currently this project is built against the .Net framework 4.0 and MVC 4
  • I want to support MVC 5 for this project
  • To support MVC 5, I’d need to upgrade the project to use .Net framework 4.5
  • This would mean that developers still running .Net framework 4.0 would no longer be able to use my updated project

I also don’t want to have to create different projects and assemblies that target specific MVC versions (in this case you’d end up with assembly names like MyProject.MVC4.dll and MyProject.MVC5.dll). I have seen this done with other solutions and it works but I feel it is not necessary unless your project is using specific functionality from a particular MVC version.

In my case my project will compile perfectly against MVC 4 and 5 without any codebase changes so I’m not actually targeting against a specific MVC version ( >= 4 ). If your project uses specific functionality from the different MVC versions I think you will have to output different assemblies like MyProject.MVC5.dll. In that case this post will probably help: http://blogs.korzh.com/2013/12/nuget-package-different-mvc-versions.html

The goal

The end result is that I want a single project file that has 4 build configurations:

  • Debug / Release
    • These will build against .Net 4.0
    • This will reference MVC 4
  • Debug-Net45 / Release-Net45
    • This will build against .Net 4.5
    • This will reference MVC 5

Each of these build configurations exports the same assembly name: MyProject.dll

I then want a single NuGet package which will install the correct DLL based on the .Net version that the user has installed.

How it’s done

Build configuration setup

To start with you’ll have a project that targets .Net framework 4.0 and references MVC 4 and 2 standard build configurations: Debug, Release.

First we need to create 2 new build configurations: Debug-Net45 and Release-Net45 and have these configurations output the DLLs to a custom folder. To do this we launch the Configuration Manager:

2014-04-30_2014

Create a new build configuration:

2014-04-30_2016

Enter the name of the new configuration and copy the configuration from it’s associated existing one. So Debug-Net45 would copy from Debug and Release-Net45 copies from Release.

2014-04-30_2021

Do this for both configurations – Debug-Net45 and Release-Net45.

Project setup

The next step requires manually editing your .csproj file since Visual Studio doesn’t want to normally allow you to do this. This is how you can configure each build type to target a different framework version. You’ll first need to find these 2 entries:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

Inside each of these elements you need to explicitly tell these build configurations to use .Net framework 4.0 by adding this element:

<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>

Next you’ll want to copy/paste both of these property groups and:

  • Change the Condition to check for the new build configurations and to target .Net framework 4.5
  • Change the OutputPath to have a specific .Net 4.5 folder
  • Change the TargetFrameworkVersion to be .Net 4.5

You should end up with 2 new elements that look something like:

<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-Net45|AnyCPU'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\Debug-Net45\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <DebugType>full</DebugType>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <ErrorReport>prompt</ErrorReport>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release-Net45|AnyCPU'">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release-Net45\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>

Next we need to do this for the MVC references or any framework specific references you need to target. In this example it is just the MVC references and you’ll need to wrap them with an ItemGroup element, you’ll end up with something like this to target the MVC 4 libs:

<ItemGroup Condition=" '$(Configuration)'=='Debug' Or '$(Configuration)'=='Release'">
    <Reference Include="System.Web.Helpers, Version=2.0.0.0, .....">
      <Private>True</Private>
      <HintPath>
        ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll
      </HintPath>
    </Reference>
    <Reference Include="System.Web.Mvc, Version=4.0.0.0, .....">
      <Private>True</Private>
      <HintPath>
        ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll
      </HintPath>
    </Reference>
    <Reference Include="System.Web.Razor, Version=2.0.0.0, .....">
      <Private>True</Private>
      <HintPath>
        ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll
      </HintPath>
    </Reference>
    <Reference Include="System.Web.WebPages, Version=2.0.0.0, .....">
      <Private>True</Private>
      <HintPath>
        ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll
      </HintPath>
    </Reference>
    <Reference Include="System.Web.WebPages.Deployment, Version=2.0.0.0, .....">
      <Private>True</Private>
      <HintPath>
        ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll
      </HintPath>
    </Reference>
    <Reference Include="System.Web.WebPages.Razor, Version=2.0.0.0, .....">
      <Private>True</Private>
      <HintPath>
        ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll
      </HintPath>
    </Reference>
</ItemGroup>

Then we need to go ahead and copy/paste this block but target the different build configurations and then swap out these MVC 4 version references with the MVC 5 version references.

Nuget package restore

For this tutorial I’m assuming you are using Nuget to reference your MVC libs and an easy way to get Nuget to play reasonably with this setup is to enable Nuget package restore for your solution – right click on your solution and click the button:

2014-05-01_1625

Then in your packages.config file you can manually add the MVC 5 references:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.AspNet.Mvc" 
           version="4.0.30506.0" targetFramework="net40" />
  <package id="Microsoft.AspNet.Razor" 
           version="2.0.30506.0" targetFramework="net40" />
  <package id="Microsoft.AspNet.WebPages" 
           version="2.0.30506.0" targetFramework="net40" />
  <package id="Microsoft.Web.Infrastructure" 
           version="1.0.0.0" targetFramework="net40" />
  
  <package id="Microsoft.AspNet.Mvc" 
           version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.Razor" 
           version="3.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebPages" 
           version="3.0.0" targetFramework="net45" />
</packages>

Now when you build your solution under the different build configurations Nuget will automatically go and get the correct MVC versions based on the current .Net Framework version.

Thats it!

With all of this in place it should ‘just work’ :) You will notice some odd looking icons in your references list in Visual Studio but it’s nothing to worry about, Visual Studio is just confused because it isn’t familiar with how you’ve tricked it!

2014-05-01_1709

So now when you build using your different build configurations, it will output the correct DLLs to the correct build folders:

  • Both Debug & Release will output to /bin/Debug & bin/Release with MVC 4 libraries and the MyProject.dll will be compiled against .Net Framework 4.0
  • Both Debug-Net45 & Release-Net45 will be output to /bin/Debug-Net45 & /bin/Release-Net45 with MVC 5 libraries and the MyProject.dll will be compiled against .Net Framework 4.5

And here’s some proof:

2014-05-01_1714

2014-05-01_1715

If you are using some automated build processes with MSBuild you can then just target the build configuration names you’d like to export.

The Nuget setup is pretty simple since you can target your dependencies by framework:

<group targetFramework="net40">
<!--between 4 and less than version 5-->
<dependency id="Microsoft.AspNet.Mvc" version="(4.0.20710,5)" />
</group>

<group targetFramework="net45">
<!--between 4 and less than version 6 (who knows what'll happen then)-->
<dependency id="Microsoft.AspNet.Mvc" version="(4.0.20710,6)" />
</group>

Then for each of your lib files in Nuget you ensure that you output them to the framework specific /lib folders such as:

target="lib\net40"
target="lib\net45"

This process has been implemented for the Client Dependency Framework version 1.8.0 to support MVC 4 and 5 without having to change the assembly name.

Custom MVC routing in Umbraco

July 4, 2013 23:00

This post will describe how you can declare your own custom MVC routes in order to execute your own custom controllers in Umbraco but still be able to render Umbraco views with the same model that Umbraco uses natively.

NOTE: This post is not about trying to execute a particular Umbraco page under a custom URL, that functionality can be accomplished by creating a custom IContentFinder (in v6.1), or by applying the umbracoUrlAlias

There’s a long (but very useful) thread on Our describing various needs for custom MVC routing inside of Umbraco, definitely worth a read. Here I’ll try to describe a pretty easy way to accomplish this. I’m using Umbraco v6.0.7 (but I’m pretty sure this will work in v4.10+ as well).

Create the route

This example will use an IApplicationEventHandler (in 6.1 you should use the base class ApplicationEventHandler instead). Here I’m defining a custom route for handling products on my website. The example URLs that I want handled will be:

  • /Products/Product/ProductA
  • /Products/Category/CategoryA

 

public class MyStartupHandler : IApplicationEventHandler
{
    public void OnApplicationStarted(
        UmbracoApplicationBase umbracoApplication, 
        ApplicationContext applicationContext)
    {
        //Create a custom route
        RouteTable.Routes.MapRoute(
            "test",
            "Products/{action}/{id}",
            new
                {
                    controller = "MyProduct", 
                    action = "Product", 
                    id = UrlParameter.Optional
                });           
    }
    public void OnApplicationInitialized(
        UmbracoApplicationBase umbracoApplication, 
        ApplicationContext applicationContext)
    {
    }
    public void OnApplicationStarting(
        UmbracoApplicationBase umbracoApplication, 
        ApplicationContext applicationContext)
    {
    }
}

Create the controller

With the above route in place, I need to create a controller called “MyProductController”. The base class it will inherit from will be “Umbraco.Mvc.PluginController”. This abstract class exposes many of the underlying Umbraco objects that I might need to work with such as an UmbracoHelper, UmbracoContext, ApplicationContext, etc… Also note that the PluginController doesn’t get auto-routed like a SurfaceController which is good because we only want to route our controller once. In 6.1 you can inherit from a different controller called Umbraco.Mvc.UmbracoController, which is what the PluginController will be inheriting from in the next version.

Constructor

First thing is to define the constructors since the PluginController doesn’t have an empty constructor but we want ours to (unless you have IoC setup).

public class MyProductController : PluginController
{
    public MyProductController()
        : this(UmbracoContext.Current)
    {            
    }

    public MyProductController(UmbracoContext umbracoContext) 
        : base(umbracoContext)
    {
    }
}

Actions

Next we need to create the controller Actions. These actions will need to lookup either a Product or a Category based on the ‘id’ string they get passed. For example, given the following URL: /Products/Category/CategoryA the id would be CategoryA and it would execute on the Category action.

In my Umbraco installation, I have 2 document types with aliases: “Product” and “ProductCategory”

image

To perform the lookup in the controller Actions we’ll use the UmbracoHelper.TypedSearch overload which uses Examine.

public ActionResult Category(string id)
{
    var criteria = ExamineManager.Instance.DefaultSearchProvider
        .CreateSearchCriteria("content");
    var filter = criteria.NodeTypeAlias("ProductCategory").And().NodeName(id);
    var result = Umbraco.TypedSearch(filter.Compile()).ToArray();
    if (!result.Any())
    {
        throw new HttpException(404, "No category");
    }
    return View("ProductCategory", CreateRenderModel(result.First()));
}

public ActionResult Product(string id)
{
    var criteria = ExamineManager.Instance.DefaultSearchProvider
        .CreateSearchCriteria("content");
    var filter = criteria.NodeTypeAlias("Product").And().NodeName(id);
    var result = Umbraco.TypedSearch(filter.Compile()).ToArray();
    if (!result.Any())
    {
        throw new HttpException(404, "No product");
    }
    return View("Product", CreateRenderModel(result.First()));
}

The Category action lookup uses Examine to lookup any document with:

  • A document type alias of “ProductCategory”
  • A name equal to the id parameter passed in

The Product action lookup uses Examine to lookup any document with:

  • A document type alias of “Product”
  • A name equal to the id parameter passed in

The result from TypedSearch is IEnumerable<IPublishedContent> and since we know we only want one result we pass in the first item of the collection in “result.First()”

If you didn’t want to use Examine to do the lookup, you could use a Linq query based on the result of Umbraco.TypedContentAtRoot(), but I wouldn’t recommend that since it will be much slower.

In v6.1 the UmbracoHelper exposes a couple of other methods that you could use to perform your lookup if you didn’t want to use Examine and wanted to use XPath instead:

  • TypedContentSingleAtXPath(string xpath, params XPathVariable[] vars)
  • TypedContentAtXPath(string xpath, params XPathVariable[] vars)
  • TypedContentAtXPath(XPathExpression xpath, params XPathVariable[] vars)

CreateRenderModel method

You will have noticed that I’m using a method called CreateRenderModel to create the model that is passed to the View. This method accepts an IPublishedContent object as an argument and creates a RenderModel object which is what a normal Umbraco view expects. This method isn’t complex but it does have a couple things worth noting:

private RenderModel CreateRenderModel(IPublishedContent content)
{
    var model = new RenderModel(content, CultureInfo.CurrentUICulture);

    //add an umbraco data token so the umbraco view engine executes
    RouteData.DataTokens["umbraco"] = model;

    return model;
}

The first thing is that you need to construct the RenderModel with an explicit culture otherwise you’ll get an exception. The next line adds the created RenderModel to the RouteData.DataTokens… this is because we want to render an Umbraco view which will be stored in either of the following places (based on Umbraco standard practices):

  • ~/Views/Product.cshtml
  • ~/Views/ProductCategory.cshtml

These locations are not MVC standard practices. Normally MVC will look in a controller specific folder for views. For this custom controller the locations would be:

  • ~/Views/MyProduct/Product.cshtml
  • ~/Views/MyProduct/ProductCategory.cshtml

But we want to use the views that Umbraco has created for us so we need to ensure that the built in Umbraco ViewEngine gets executed. For performance reasons the Umbraco RenderViewEngine will not execute for a view unless a RenderModel instance exists in the RouteData.DataTokens with a key of “umbraco”, so we just add it there before we return the view.

Views

The views are your regular Umbraco views but there’s a few things that might not work:

  • Macros. Sorry, since we’ve bypassed the Umbraco routing pipeline which macros rely upon, any call to Umbraco.RenderMacro will fail. But you should be able to achieve what you want with Partial Views or Child Actions.
  • Umbraco.Field. Actually this will work but you’ll need to upgrade to 6.0.7 or 6.1.2 based on this fixed issue: http://issues.umbraco.org/issue/U4-2324

One cool thing is that you can use the regular MVC UrlHelper to resolve the URLs of your actions, since this custom controller is actually just a regular old MVC controller after all.

These view example are nothing extraordinary, just demonstrating that they are the same as Umbraco templates with the same model (but using our custom URLs)

ProductCategory

@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = null;
}
<html>
    <body>
        <h1>Product category</h1>
        <hr />
        <h2>@Model.Content.Name</h2>
        <ul>
            @foreach (var product in Model.Content.Children
                .Where(x => x.DocumentTypeAlias == "Product"))
            {
                <li><a href="@Url.Action("Product", "MyProduct", new { id = product.Name })">
                        @product.Name
                    </a>
                </li>
            }
        </ul>
    </body>
</html>

Which looks like this:

image

Product

@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = null;
}
<html>
    <body>

        <h1>Product</h1>
        <hr />
        <h2>@Model.Content.Name</h2>
        <div>
            @(Model.Content.GetPropertyValue("Description"))
        </div>
    </body>
</html>

Which looks like this:

image

Whats next?

With the setup above you should be able to achieve most of what you would want with custom routing, controllers, URLs and lookups. However, as I mentioned before things like executing Macros and potentially other internal Umbraco bits that rely on objects like the PublishedContentRequest will not work.

Of course if there is a will, there is a way and I have some cool ideas that could make all of those things work seamlessly too with custom MVC routes. Stay tuned!

Razor + dynamic + internal + interface & the 'object' does not contain a definition for 'xxxx' exception

April 11, 2013 16:49

I’ve come across this strange issue and decided to blog about it since I can’t figure out exactly why this is happening it is clearly something to do with the DLR and interfaces.

First, if you are getting the exception: 'object' does not contain a definition for 'xxxx' it is related to either an object you have being marked internal or you are are using an anonymous object type for your model (which .Net will always mark as internal).

Here’s a really easy way to replicate this:

1. Create an internal model

internal class MyModel
{
public string Name {get;set;}
}

2. Return this model in your MVC action

public ActionResult Index()
{
return View(new InternalTestModel("Shannon"));
}

3. Make your view have a dynamic model and then try to render the model’s property

@model dynamic
<h1>@Model.Name</h1>

You’ll get the exception:

Server Error in '/' Application.

'object' does not contain a definition for 'Name'

So even though the error is not very informative, it makes sense since Razor is trying to access an internal class.

Try using a public interface

Ok so if we want to keep our class internal, we could expose it via a public interface. Our code might then look like this:

public interface IModel 
{
string Name {get;}
}
internal class MyModel : IModel
{
public string Name {get;set;}
}

Then we can change our view to be strongly typed like:

@model IModel
<h1>@Model.Name</h1>

And it will work, however if you change your view back to be @model dynamic you will still get the exception. Pretty sure it’s because the DLR is just binding to the instance object and doesn’t really care about the interface… this makes sense.

Try using an abstract public class

For some reason if you make your internal class inherit from a public abstract class that implements the same interface you will not get this exception even though the object instance you are passing to razor is internal. For example with this structure:

public interface IModel 
{
string Name {get;}
}
public abstract class ModelBase : IModel
{
public abstract Name {get;}
}
internal class MyModel : IModel
{
public override string Name {get;set;}
}

You will not get this error if your view is @model dynamic.

Strange!

I’m sure there’s something written in the DLR spec about this but still seems strange to me! If you are getting this error and you aren’t using anonymous objects for your model, hopefully this might help you figure out what is going on.

Using IoC with Umbraco & MVC

October 31, 2012 18:08

The question was asked on my post yesterday about the upcoming Umbraco 4.10.0 release with MVC support and whether it is possible to use IoC/Dependency Injection with our implementation. The answer is definitely yes!

One of the decisions we’ve made for the code of Umbraco is to not use IoC in the core. This is not because we don’t like IoC (in fact I absolutely love it) but more because things start to get really messy when not 100% of your developers understand it and use it properly. Since Umbraco is open source there are developers from many walks of life committing code to the core and we’d rather not force a programming pattern on them. Additionally, if some developers don’t fully grasp this pattern this leads to strange and inconsistent code and even worse if developers don’t understand this pattern then sometimes IoC can be very difficult to debug.

This ultimately means things are better for you since we won’t get in the way with whatever IoC framework you choose.

Which frameworks can i use?

Theoretically you can use whatever IoC framework that you’d like, though I haven’t tested or even tried most of them I’m assuming if they are reasonable frameworks that work with MVC then you should be fine. I’m an Autofac fan and to be honest I’ve only dabbled in other frameworks so all examples in this post and documentation are based on Autofac. Since we don’t use any IoC, it also means that we are not specifying a DependencyResolver so you are free to set this to whatever you like (I’d assume that most IoC frameworks would integrate with MVC via the DependencyResolver).

How do i do it?

I chucked up some docs on github here which I’ll basically just reiterate on this post again with some more points. Assuming that you construct your IoC container in your global.asax, the first thing you’ll have to do is to create this class and make sure it inherits from the Umbraco one (otherwise nothing will work). Then just override OnApplicationStarted and build up your container. Here’s an example (using Autofac):

/// <summary>
/// The global.asax class
/// </summary>
public class MyApplication : Umbraco.Web.UmbracoApplication
{
    protected override void OnApplicationStarted(object sender, EventArgs e)
    {
        base.OnApplicationStarted(sender, e);

        var builder = new ContainerBuilder();

        //register all controllers found in this assembly
        builder.RegisterControllers(typeof(MyApplication).Assembly);

        //add custom class to the container as Transient instance
        builder.RegisterType<MyAwesomeContext>();

        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }
}

Notice that I’ve also registered a custom class called MyAwesomeContext in to my container, this is just to show you that IoC is working. Of course you can do whatever you like with your own container :) Here’s the class:

public class MyAwesomeContext
{
    public MyAwesomeContext()
    {
        MyId = Guid.NewGuid();
    }
    public Guid MyId { get; private set; }
}

Next we’ll whip up a custom controller to hijack all routes for any content item that is of a Document Type called ‘Home’ (there’s documentation on github about hijacking routes too):

public class HomeController : RenderMvcController
{
    private readonly MyAwesomeContext _myAwesome;

    public HomeController(MyAwesomeContext myAwesome)
    {
        _myAwesome = myAwesome;
    }

    public override ActionResult Index(Umbraco.Web.Models.RenderModel model)
    {
        //get the current template name
        var template = this.ControllerContext.RouteData.Values["action"].ToString();
        //return the view with the model as the id of the custom class
        return View(template, _myAwesome.MyId);
    }
}

In the above controller, a new instance of MyAwesomeContext will be injected into the constructor, in the Index action we’re going to return the view that matches the currently routed template and set the model of the view to the id of the custom MyAwesomeContext object (This is just an example, you’d probably do something much more useful than this).

We can also do something similar with SurfaceControllers (or any controller you like):

public class MyTestSurfaceController : SurfaceController
{
    private readonly MyAwesomeContext _myAwesome;

    public MyTestSurfaceController(MyAwesomeContext myAwesome)
    {
        _myAwesome = myAwesome;
    }

    [ChildActionOnly]
    public ActionResult HelloWorld()
    {
        return Content("Hello World! Here is my id " + _myAwesome.MyId);
    }
}

That’s it?

Yup, these are just examples of creating controllers with IoC, the actual IoC setup is super easy and should pretty much work out of the box with whatever IoC framework you choose. However, you should probably read the ‘Things to note’ in the documentation in case your IoC engine of choice does something wacky with the controller factory.

Native MVC support in Umbraco coming very soon!

October 31, 2012 00:07

Its been a while since writing a blog post! … but that’s only because I can never find the time since I’m still gallivanting around the globe :P

But this post is about something very exciting, and I’m sure most of you that are reading this already know that with the upcoming Umbraco 4.10.0 release (currently in Beta and downloadable here) we are natively supporting ASP.Net MVC! What’s more is that I’ve tried to document as much as I could on our GitHub docs. Once my pull request is completed the docs will all be available on the main site but until then you can see them on my fork here.

So where to begin? Well, I’m going to try to keep this really short and sweet because I’m hoping you can find most of the info that you’ll want in the documentation.

What is supported?

Everything that you can do in MVC you will be able to do in Umbraco’s MVC implementation. Anything from Partial Views, Child Actions, form submissions, data annotations, client validation to Surface Controllers, custom routes and hijacking Umbraco routes.  If you have used Razor macros before, we support a very similar syntax but it is not 100% the same. We support most of the dynamic querying that you use in Razor macros with the same syntax but to access the dynamic model is slightly different. What is crazy awesome super cool though is that we support a strongly typed query structure!! :) So yes, you can do strongly typed Linq queries with intellisense, no problemo!

Still using Web forms? not a problem, you can have both Web forms and MVC engines running in tandem on your Umbraco site. However, a config setting will set a default rendering engine which will determine whether Web forms master pages or MVC views are created in the back office.

What is not supported (yet)

There’s a few things in this release that we’ve had to push to 4.11.0 due to time constraints. They include: Better tooling support for the View editors in the back office, Partial View Macros and Child Action Macros. Though once you start using this MVC version you’ll quickly discover that the need for macros is pretty small. Perhaps people use macros in different ways but for the most part with the way that MVC works I would probably only use macros for rendering macro content in the WYSIWYG editor.

We support rendering any macros in MVC so you can even render your XSLT macros in your views, but issues will arise if you have User Control or Web form control macros that contain form elements. You will still be able to render these macros but any post backs will not work, and will most likely cause a YSOD. Unfortunately due to the vast differences between how Web forms and MVC work in ASP.Net this is something that we cannot support. The good news is that creating forms in MVC is super easy and makes a whole lot more sense than Web forms…. you can even have more than one <form> element on a page, who’d have thought :P

Strongly typed queries

You can find the documentation for this here but I just wanted to point out some of the differences between the strongly typed syntax and the dynamic syntax. First, in your view you have two properties:

  • @Model.Content = the strongly typed model for your Umbraco view which is of type: Umbraco.Core.Models.IPublishedContent
  • @CurrentPage = the dynamic model representing the current page, this is very very similar to the @Model property in Razor macros

An example is to get the current page’s children that are visible, here’s the syntax for both (and of course since the @CurrentPage is dynamic, you will not get intellisense):

//dynamic access
@CurrentPage.Children.Where("Visible")

//strongly typed access
@Model.Content.Children.Where(x => x.IsVisible())

There are also some queries that are just not (yet) possible in the dynamic query structure. In order to get some complex queries to work with dynamic linq, we need to code these in to the parser to create the expression tree. The parser could probably do with more TLC to support things like this but IMHO, we’re just better off using the strongly typed way instead (plus its probably a much faster execution). I’ve listed this as an example in the docs but will use it here again:

//This example gets the top level ancestor for the current node, and then gets 
//the first node found that contains "1173" in the array of comma delimited
//values found in a property called 'selectedNodes'.
//NOTE: This is one of the edge cases where this doesn't work with dynamic execution but the
//syntax has been listed here to show you that its much easier to use the strongly typed query
//instead

//dynamic access
var paramVals = new Dictionary<string, object> {{"splitTerm", new char[] {','}}, {"searchId", "1173"}};
var result = @CurrentPage.Ancestors().OrderBy("level")
.Single()
.Descendants()
.Where("selectedNodes != null && selectedNodes != String.Empty && selectedNodes.Split(splitTerm).Contains(searchId)", paramVals)
.FirstOrDefault();

//strongly typed
var result = @Model.Content.Ancestors().OrderBy(x => x.Level)
.Single()
.Descendants()
.FirstOrDefault(x => x.GetPropertyValue("selectedNodes", "").Split(',').Contains("1173"));

IMHO i much prefer the strongly typed syntax but it’s up to you to decide since we support both structures.

UmbracoHelper

Another class we’ve introduced is called the Umbraco.Web.UmbracoHelper which is accessible on your views by using the @Umbraco syntax and is also accessible on any SurfaceController. This class contains a ton of handy methods, it is basically the ‘new’ Umbraco ‘library’ class (you know that static one that has a lower case ‘l’ :P ) Of course the ‘library’ class will still be around and you can still use it in your views… but you shouldn’t! This new helper class should contain all of the methods that you need from querying content/media by ids, rendering macros and rendering field content, to stripping the html from a string. The library class was designed for use in Xslt where everything from c# wasn’t natively given to you, now with Razor views you have the entire world of c# at your fingertips. So you’ll notice things like the date formatting functions that were on ‘library’ are not on the UmbracoHelper, and that is because you can just use the regular c# way. Though, if you feel inclined that these methods should be on UmbracoHelper, another great thing is that this is not a static class so you can add as many extension methods as you like.  I’d list all of the methods out here but I said I’d keep it short, your best bet currently is to just have a look at the class in the source code, or just see what great stuff shows up in intellisense in VS.

UmbracoContext

Though we did have another UmbracoContext class, this one is the new cooler one and the old one has been marked as obsolete. This new one’s full name is Umbraco.Web.UmbracoContext and it is a singleton so you can access it by UmbracoContext.Current but normally you shouldn’t have to access it by it’s singleton because it is available in all of your views and SurfaceControllers as a property. For example, to access the UmbracoContext in your view you simply use @UmbracoContext. This class exposes some handy properties like: UmbracoUser, PageId, IsDebug, etc…

Testing

If you are interested in MVC and Umbraco, it would be really really appreciated for you to take the time to download the beta, the latest nightlies or source code and give it a shot. Hopefully the docs are enough to get you up and running and if you run into any troubles please log your issues on the tracker. If you have any question, comments, etc… about the source code we’d love to hear from you on the mail list.

Pete will be putting up an MVC getting started post on the Umbraco blog real soon, so watch this space!

Adios!

MVC in Umbraco v4

June 18, 2012 07:33

After the announcement of discontinuing Umbraco v5 development during this years Code Garden 2012 conference, the biggest question seemed to be: What will happen with ASP.Net MVC and Umbraco. We held an open space session regarding this question where we asked 2 questions: “Is an MVC implementation in Umbraco important to have for the front end?” and “Is an MVC implementation important to have for the back office?”. There were quite a few people who attended this session and I think 100% of people raised their hands in answer to the first question and only 1 person raised their hands for the second answer.  I think this result was expected since most Umbraco developers simply wish to use MVC in their own development on the front-end and want the Umbraco back office to keep working with all of the great packages already created for it.

There was a considerable amount of knowledge gained in creating v5 and of course we will incorporate much of this knowledge into v4… starting real soon! I decided to create a package for Umbraco v4 which enables a native MVC front end which was demo’d during the Code Garden package competition and is available right now!  It turns out that creating this didn’t take much time at all, in fact I created it during the 2nd day of the conference. The reason this was reasonable easy was because we had all of this already built for v5 so it was a matter of taking this knowledge and code and applying it to v4.

So if you are like many other devs and really want Umbraco to route to a native MVC front end then you can give this package a try, its called umbraMVCo. Please be warned that I have not tested this very much, but also know that its just using the tried and tested v4 api’s to do the routing so I’m assuming it will ‘just work’ … though I’m sure you guys will find some bugs I haven’t yet :) There’s also a readme file on the downloads page which explains how to install it, and what settings/servers that I know it works with.

What’s also really cool is this code completely supports Hijacking Umbraco Routes!

Download/Source

You can download the package and readme files here

https://bitbucket.org/Shandem/umbramvco/downloads

Ensure that you read the readme file, it contains some very important information including installation instructions!

The source can be found here:

https://bitbucket.org/Shandem/umbramvco/src

If you come across issues with this please log issues here: https://bitbucket.org/Shandem/umbramvco/issues . The source isn’t really complicated or anything though so you should be able to identify the reason for an issue if you come across it.

What’s next?

So will MVC be coming to v4… Yes indeed. We will also support routing to either WebForms or MVC and we’ll support this by having a flag on the document type to choose which rendering engine to use. We’ve got a few things to do in v4 regarding how routing works to do this nicely/properly but the end result will be pretty much the same as what this package enables. All of those cool MVC things that you liked in v5 like SurfaceControllers will be coming to v4 as well, we will still support Child Action and Partial View macros. Another cool thing is that we should be able to support Xslt and UserControl macros in MVC as well (though any post backs will definitely not work).

So even though the development of v5 has been discontinued, a ton of the concepts that you liked about it will in fact be ported to v4.