Jan 15 2018

2.1.0 release of the Mvc Controls Toolkit Core

Category: MVC | Asp.net | Asp.net coreFrancesco @ 05:53

2.1.0 release of the #AspNetCore  Mvc Controls Toolkit. See release notes  and live examples.

Tags: ,

Oct 4 2017

Building Web applications with Knockout.js and ASP.NET core

Category: Asp.net | Asp.net core | MVC | TypeScript | WebApi | JavaScriptFrancesco @ 05:40

Amongst all the client side frameworks backed by big companies, React.js and Angular.js appear to be the most popular. However, Knockout.js still maintains a good market share, thanks to its interesting peculiarities.

Knockout is based on an MVVM paradigm similar to Angular.js, but unlike React.js. While it is adequate for modular complex applications, at the same time, it is very simple to mix with server side templating, similar to React.js, but unlike Angular.js….Read full article

Contact us if you want to learn more

aspnet-core-running-spa

Tags: , ,

Sep 27 2017

2.0.0 release of the Mvc Controls Toolkit compatible with Asp.net Core 2.0

Category: Asp.net core | MVC | Asp.netFrancesco @ 07:15

2.0.0 release of the #AspNetCore (2.0 and 1.1) Mvc Controls Toolkit. See release notes  and live examples.

Tags: ,

Aug 1 2017

1.2.7 release of the Asp.net core Mvc Controls Toolkit

Category: Asp.net | MVC | Asp.net coreFrancesco @ 21:29

1.2.7 release of the #AspNetCore Mvc Controls Toolkit. See release notes  and live examples..

Tags: ,

Jul 13 2017

#Asp.net Core Mvc Controls Toolkit complete tutorial on @DotNetCurry

Category: MVC | Asp.net core | Asp.netFrancesco @ 22:30

Available complete Mvc Controls Toolkit Core tutorial on @DotNetCurry. Enjoy it!

Build a complete ASP.NET MVC Core web application from the DB layer to the UI using the Mvc Controls toolkit core free library. We will also show data from a database in a paged Grid with filtering/sorting/grouping and add/edit/delete capabilities….Read full article,

 

mvc-controls-toolkit-install

Tags: ,

Jun 26 2017

New 1.2.5 release of the Asp.net core Mvc Controls Toolkit

Category: Asp.net | Htnl5 fallback | MVCFrancesco @ 05:55

The new 1.2.5 release of the Asp.net core Mvc Controls Toolkit is ready for download. Play live with ajax sorting, filtering and grouping. Now, thanks to full ajax support, you may have several independent grids in the same page! Each grid may have an ajax “back button” to go back to its previous query.

Several Grid

Install in your project and follow Quickstart

Tags: ,

May 9 2017

Customization And Localization Of ASP.NET Core MVC Default Validation Error Messages

Category: MVC | Asp.net core | Asp.netFrancesco @ 00:25

This time my post has been published on the MSDN Blog! Enjoy it!.

………Moreover, the new validation provider architecture made it easy to override the default messages built-in, in the .Net validation attributes with customized default messages defined in resource files. This way, the user can provide global custom messages once and for all, thus avoiding the burden of having to specify an error message in each occurrence, of each attribute.This article goes into detail about how to customize both all ASP.NET MVC specific error messages, and all default messages coming from validation attributes……Read full article

Tags: , , , , ,

May 7 2017

Asp.net core: Deserializing Json with Dependency Injection

Category: MVC | Asp.net core | Asp.netFrancesco @ 21:30

Custom Model Binding in Asp.net Core, 3: Model Binding Interfaces

In a previous post I discussed how to model bind Interfaces/abstract classes with the help of Asp.net core dependency injection features. However, the technique discussed there doesn’t apply to Json data added to the request body, since request body is processed by the BodyModelBinder that, in turn, selects a formatter based on the request content-type header. The formatter for “application/json” is a wrapper for Json.net, so the code of our previous “interfaces model binder” is never called, and also if called it wouldn’t be able to process Json data in the request body.

The behavior of Json.net serializer/deserializer may be customized through an MvcJsonOptions options object.In this post I am going to show how to modify Json.net behavior so that it attempts to use Dependency Injection to create any .Net object before creating it through its constructor. This, will enable not only the deserialization of interfaces, but also the customization of object creation through Asp.net Core DI engine.

Preparing the project

As a first step let create a new asp.net core project named “JsonDI”:

Project

Select “no authentication” to simplify the code created by VS project template.

Then let create a new folder called “Models” and add it the following “IPerson.cs” file, that contains both an interface definition and its default implementation:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace JsonDI.Models
{
    public interface IPerson
    {
       string Name { get; set; }
       string Surname { get; set; }
    }
    public class DefaultPerson: IPerson
    {
        public string Name { get; set; }
        public string Surname { get; set; }
    }
}

Now let modify the code of the Home controller to add an HttpPost for the Index action:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using JsonDI.Models;

namespace JsonDI.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
        [HttpPost]
        public IActionResult Index([FromBody] IPerson model)
        {
            return Json(model);
        }
        ....
        ....

We need an Ajax call to send Json data to our newly created HttpPost action method. Go to the Index.cshtml file in the Views/Home folder and substitute its code with the code below:

@{
    ViewData["Title"] = "Deserialization with DI";
}

<h2>@ViewData["Title"]</h2>

<form asp-action="Index" asp-controller="Home">
    
    <button data-url="@Url.Action("Index", "Home")" type="button" class="test btn btn-default">Submit</button>
</form>
@section Scripts
{
    <script type="text/javascript">
        $(".test").click(function (evt) {
            var url = $(evt.target).attr("data-url");
            $.ajax(url,
                {
                type: 'POST',
                data: JSON.stringify({
                    name: "Francesco",
                    surname: "Abbruzzese"
                }),
                success: function () { alert("message received"); },
                contentType: "application/json",
                dataType: 'json'
            });
        });
    </script>
}

Now place a breakpoint here:

Breakpoint

…and run the project.

When we click the “Submit” button an Ajax request is issued to our HomeController that contains an IPerson interface in the request body. However, when the breakpoint is hit, we may verify that the model parameter is null! In fact Json.net is not able to deserialize the IPerson interface because it doesn’t know how to create an instance of it.

Enriching Asp.net Core Dependency Injection.

Pieces of code that need Asp.net Core Dependency Injection engine creates type instances do it through the IServiceProvider interface that contains the unique method “GetService(Type t)”. Accordingly, we may create a type instance calling GetService or some other extension method that, in turn, calls it, but we are not able to ask if a type has been registered with the DI engine. This problem may be solved using a third party DI engine, such as Autofac. In this section we will show how to add this capability without using third party DI engines.

Let add an “Extensions” folder to the project. We will place there all extensions we need to have Json.net use DI. As a first step let define an interface containing all features we need and that are not exposed by IServiceProvider:

using System;

namespace JsonDI.Extensions
{
    public interface IDIMeta
    {
        bool IsRegistred(Type t);
        Type RegistredTypeFor(Type t);
    }
}

I called it IDIMeta because it provides meta-information about the content of the the DI container. The first method returns if a type has been registered with the DI engine, and the second returns the type that will be actually created when requiring an instance of the registered type.

The actual implementation of the above interface uses the IServiceCollection available in the ConfigureServices method of the Startup.cs class to collect all information needed to implement the interface methods in a dictionary :

using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;

namespace JsonDI.Extensions
{
    public class DIMetaDefault: IDIMeta
    {
        IDictionary<Type, Type> register = new Dictionary<Type, Type>();
        public DIMetaDefault(IServiceCollection services)
        {
            foreach (var s in services)
            {
                register[s.ServiceType] = s.ImplementationType;
            }
        }
        public bool IsRegistred(Type t)
        {
            return register.ContainsKey(t);
        }

        public Type RegistredTypeFor(Type t)
        {
            return register[t];
        }
    }
}

As a final step we need to register IDIMeta itself in the DI engine, by adding the code below to the ConfigureServices method of the Startup.cs class:

services.TryAddSingleton<IDIMeta>(s =>
{
    return new DIMetaDefault(services);
});

Later on we will show the whole code to be added to the ConfigureServices method of the Startup.cs class.

Customizing Json.net behavior

Now we are ready to customize Json.net behavior! The way Json.net serializes/deserializes types is specified by ContractResolvers. ContractResolvers return a “contract” for each type that contains all information on how to deal with that type. In particular each contract specifies how to create an instance of the type and how to fill its properties. The way to fill type properties may be customized by passing a custom converter in the “Converter” property of the contract. However, we don’t need custom converters since we must customize just the way types are created.

Our custom ContractResolver inherits form the built-in “CamelCasePropertyNamesContractResolver” that is the one used as a default by Asp.net Core:

using System;
using Newtonsoft.Json.Serialization;

namespace JsonDI.Extensions
{
    public class DIContractResolver: CamelCasePropertyNamesContractResolver
    {
        IDIMeta diMeta;
        IServiceProvider sp;
        public DIContractResolver(IDIMeta diMeta, IServiceProvider sp)
        {
            this.diMeta = diMeta;
            this.sp = sp;
        }
        protected override JsonObjectContract CreateObjectContract(Type objectType)
        {

            if (diMeta.IsRegistred(objectType))
            {
                JsonObjectContract contract = DIResolveContract(objectType);
                contract.DefaultCreator = () => sp.GetService(objectType);

                return contract;
            }

            return base.CreateObjectContract(objectType);
        }
        private JsonObjectContract DIResolveContract(Type objectType)
        {
            var fType = diMeta.RegistredTypeFor(objectType);
            if (fType != null) return base.CreateObjectContract(fType);
            else return CreateObjectContract(objectType);
        }
    }
}

We override the CreateObjectContract method to modify the custom contract. If the type our ContractResolver has been invoked on is registered in the DI container we call DIResolveContract that, if available, returns a contract for the type that will be actually created by the DI engine. If no type is specified DIResolveContract falls back on a contract for the original type (which might have less properties than the actual type created). After that CreateObjectContract changes the contract DefaultCreator property to use DI.

Our ContractResolver needs both IServiceProvider and IDIMeta to do its job, so we passed them in its constructor.

Installing our DIContractResolver

Our DIContractResolver may be installed by configuring the MvcJsonOptions options object. In my previous posts of the custom model binding series I showed how to configure options by passing a lambda function to various extension methods in the ConfigureServices method of the Startup.cs class. We may also factor out the configuration code for each specific option object in a class by writing a class that inherits from IOption<MyOptionObject>:

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace JsonDI.Extensions
{
    public class JsonOptionsSetup: IConfigureOptions<MvcJsonOptions>
    {
        IServiceProvider serviceProvider;
        public JsonOptionsSetup(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
        }
        public void Configure(MvcJsonOptions o)
        {
            o.SerializerSettings.ContractResolver =
                new DIContractResolver(serviceProvider.GetService<IDIMeta>(), serviceProvider);
        }
    }
}

After that, it is enough to call “services.AddTransient<IConfigureOptions<MvcJsonOptions>, JsonOptionsSetup>();” in the ConfigureServices method of the Startup.cs class. Summing up the whole code of the ConfigureServices method of the Startup.cs class is:

public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();
            
            services.AddTransient<IPerson, DefaultPerson>();
            services.TryAddSingleton<IDIMeta>(s =>
            {
                return new DIMetaDefault(services);
            });
            services.AddTransient<IConfigureOptions<MvcJsonOptions>, JsonOptionsSetup>();
        }

For the above to compile properly we need the “usings” below:

using JsonDI.Extensions;
using JsonDI.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

 

That’s all! Run the project, click the submit button and wait on our previous breakpoint. This time the IPerson model contains the right data sent by the client!

Stay Tuned!

Francesco

Tags: , , , ,

Apr 5 2017

Model binding interfaces: fixing server side validation

Category: MVC | Asp.net core | Asp.netFrancesco @ 20:55

 

Custom Model Binding in Asp.net Core, 3: Model Binding Interfaces

This is a follow-up of my previous post on model binding interfaces, so please read it before going on with this post. I suppose also you have available the VS solution built in the previous post.

The problem

We use interfaces when we don’t want dependencies on how a “surface behavior” is implemented. As a matter of fact the same class may implement several interfaces and when we access it through one of these interfaces we want that each effect of the computation depends just on the way the interface is defined and not on the specific class peculiarities. In particular, we want that object validation performed through that interface depends only on the way the interface is defined.

That is why in my previous post I defined all validation attributes in the interface, instead of the interface implementation:

public interface ITestInterface
{
    [Range(1, 10)]
    int TestProperty { get; set; }
}

Unluckily, this doesn’t ensure model binder uses that validation rule. As a matter of fact the model binder has a “strange” behavior, namely if the interface is the root model received by the action method, it uses the validation attributes defined in the class that implements the interface,while if the interface is nested inside the root ViewModel received by the action method it do uses the validation attributes defined on the interface.

The reason of this behavior is quite simple: during validation the type of the root ViewModel is inferred by calling ‘GetType()’ on the model returned by the model binder, while the type of nested objects is inferred by the type of the property they are in.

About client side validation, it always uses the attributes defined in the interface.

 

In my previous post I suggested using the ‘ModelMetadataTypeAttribute’ to force usage of validation attributes defined in the interface:

[ModelMetadataType(typeof(ITestInterface))]
public class TestViewModel : ITestInterface
{
    public int TestProperty { get; set; }
}

Unluckily, this solution suffers of several problems:

  1. All validation attributes defined in the interfaces doesn’t substitute the ones defined in the class but they are simply added to them.
  2. A class may have just a single ‘ModelMetadataTypeAttribute’ so if a class implements several interfaces this technique can’t be used
  3. We cant make the class that implements the interface depends on peculiarities of the presentation layer since this would break separation of concerns between layers, thus adding the ‘ModelMetadataTypeAttribute’  just to solve a technical problem we have in the presentation layer is not a good practice.

Therefore, we are forced to modify the default behavior of the built-in validation system.

The solution

In all previous versions of Asp.net Mvc validation were performed during the model-binding recursive steps. In asp.net core, validation is performed after model binding has returned an objects tree, with a recursive visit of the whole tree. This way, the same validation process may be applied also to models that have been built by formatters (such as, for instance, the Json formatter that processes Json objects). Namely, as soon as model binding returns an objects tree an implementation of the “IObjectModelValidator” interface is retrieved through dependency injection and its “Validate” model is called passing it the model returned by the model binder and other parameters we will analyze later on in this section.

The “IObjectModelValidator” default implementation performs some preparation steps, then calls GetTipe on the model passed to its Validate method to get the root type to validate, and finally it calls a recursive visitor that traverses the whole tree for validation.

We need to substitute the default implementation with an implementation that instead of calling GetType to get the root type uses the type declared in the action method. This way instead of validating the interface implementation we might validate the interface. No modification is needed to the recursive visitor since it doesn’t use GetType but the types declared in the type properties.

Unluckily the “Validate” method is not passed the type declared in the action method but just the overall ActionContext.

The method below is able to extract the type declared in the action method from the model type extracted with GetType, the ActionContext, and initial prefix passed to the validate method. This initial prefix is either the empty string or the name of the parameter of the action method that is being processed (more details on this, later on):

private Type referenceType(string prefix, Type modelType, ActionContext actionContext)
{
    var parameterDescriptors = actionContext.ActionDescriptor.Parameters;
    ParameterDescriptor parameter;
    if (string.IsNullOrWhiteSpace(prefix))
        parameter = parameterDescriptors
            .Where(m => m.ParameterType.GetTypeInfo().IsAssignableFrom(modelType))
            .FirstOrDefault();
    else
    {
        parameter = parameterDescriptors
            .Where(m => m.Name == prefix && m.ParameterType.GetTypeInfo().IsAssignableFrom(modelType))
            .FirstOrDefault();
    }
    if (parameter != null && parameter.ParameterType.GetTypeInfo().IsInterface)
        return parameter.ParameterType;
    else return modelType;
}

We look for the parameter we need the type of in the list of all parameter descriptors.If the initial prefix is the empty string we don’t have the name of the parameter we are looking the type of, so we try to find it through the type of the model (model type must be “assignable” to the parameter type), otherwise we try a match for both name and type.

Finally if the parameter is an interface we use its type otherwise we revert to the default behavior an use the model type obtained with GetType.

The whole code of our custom implementation is :

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System.Linq;
using System.Reflection;

namespace ModelBindingInterfaces.Validation
{
    public class EnhancedObjectValidator: IObjectModelValidator
    {
        private readonly IModelMetadataProvider _modelMetadataProvider;
        private readonly ValidatorCache _validatorCache;
        private readonly IModelValidatorProvider _validatorProvider;


        public EnhancedObjectValidator(
            IModelMetadataProvider modelMetadataProvider,
            IList<IModelValidatorProvider> validatorProviders)
        {
            if (modelMetadataProvider == null)
            {
                throw new ArgumentNullException(nameof(modelMetadataProvider));
            }

            if (validatorProviders == null)
            {
                throw new ArgumentNullException(nameof(validatorProviders));
            }

            _modelMetadataProvider = modelMetadataProvider;
            _validatorCache = new ValidatorCache();

            _validatorProvider = new CompositeModelValidatorProvider(validatorProviders);
        }

        private Type referenceType(string prefix, Type modelType, ActionContext actionContext)
        {
            var parameterDescriptors = actionContext.ActionDescriptor.Parameters;
            ParameterDescriptor parameter;
            if (string.IsNullOrWhiteSpace(prefix))
                parameter = parameterDescriptors
                    .Where(m => m.ParameterType
                        .GetTypeInfo().IsAssignableFrom(modelType))
                    .FirstOrDefault();
            else
            {
                parameter = parameterDescriptors
                    .Where(m => m.Name == prefix && m.ParameterType.GetTypeInfo()
                        .IsAssignableFrom(modelType))
                    .FirstOrDefault();
            }
            if (parameter != null && parameter.ParameterType.GetTypeInfo().IsInterface)
                return parameter.ParameterType;
            else return modelType;
        }
        public void Validate(
            ActionContext actionContext,
            ValidationStateDictionary validationState,
            string prefix,
            object model)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException(nameof(actionContext));
            }

            var visitor = new ValidationVisitor(
                actionContext,
                _validatorProvider,
                _validatorCache,
                _modelMetadataProvider,
                validationState);

            var metadata = model == null ? null :
                _modelMetadataProvider
                    .GetMetadataForType(referenceType(prefix, model.GetType(),
                        actionContext));
            visitor.Validate(metadata, prefix, model);
        }
    }
}

Our custom implementation may be installed easily in the DI section of our project Startup.cs.

        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddApplicationInsightsTelemetry(Configuration);
            services.AddTransient<ITestInterface, TestViewModel>();

            services.AddMvc(o =>
            {
                o.ModelBinderProviders.Insert(0,
                    new ModelBinders.InterfacesModelBinderProvider());
            });
            services.TryAddSingleton<IObjectModelValidator>(s =>
            {
                var options = s.GetRequiredService<IOptions<MvcOptions>>().Value;
                var metadataProvider = s.GetRequiredService<IModelMetadataProvider>();
                return new EnhancedObjectValidator(metadataProvider,
                    options.ModelValidatorProviders);
            });
        }

We use the possibility offered by DI to get an instance through a Lambda, since, in the constructor of our implementation, we need the current model metadata provider that is contained in the MvcOptions object.

Proof of correctness of parameter type extraction algorithm

If you are not interested in the details of why the parameter extraction algorithm I propose always works, that is,why  it never guesses the wrong parameter you may jump this section.

In case the algorithm receives the exact parameter name, no error is possible, but what happens when it receives the empty string? There might be several parameters that are assignable from the model type, how are we sure to select the right one?

The answer is very simple: when when the algorithm receives the empty string there can’t be several parameters compatible with the model type! In fact, we receives the empty string instead of the parameter name when the name of the action method parameter is not used as a prefix in the name of any input field submitted. In fact the model binder always attempts matching field names with and without the parameter names as prefixes. Usually, we don’t add the parameter name prefix to the field names when the action method has an unique parameter, but this is not compulsory.

However, for sure, when we omit parameter names in field names we can’t have several parameters whose types share properties with the same names, otherwise the model binding process would be ambiguous. Therefore, when parameter names do not prefix field names we can’t have several parameters compatible with the same type (otherwise the properties of the model compatible with both parameters would create ambiguities).

Cautions!

Our algorithm guesses the right correctly interface type when the model binding process is invoked directly by the framework during action method parameters instantiation. However, it doesn’t work if you invoke manually model binding by calling helper functions like “TryUpdateModelAsync” from within an action method, so please, in this case do not use interfaces as parameter types.

Moreover, pay attention when using Interfaces! Validation attributes defined on interfaces are not inherited by derived interfaces or classes implementing them, since interfaces are just prescriptions and can’t furnish any “code” to the types that implement them.

 

That’s all for now

Stay tuned!

Francesco

Tags: , ,

Mar 17 2017

Custom Model Binding in Asp.net Core, 3: Model Binding Interfaces

Category: MVC | Asp.net core | Asp.netFrancesco @ 01:53


Custom Model Binding in Asp.net Core Mvc, 1

Custom Model Binding in Asp.net Core, 2: Getting Time + Client Time Zone Offset

Model binding interfaces: fixing server side validation

Asp.net core: Deserializing Json with Dependency Injection

 

In this last post of the model binding series I will discuss model binders that are not specific for a single type. That is, model binders able to handle generic types, and/or categories of types. Typical examples of these model binders are the built-in model binders for all complex types, all IEnumerables, and all dictionaries. If we give a look at all these model binders, we see that they recursively call the binding process itself to bind child elements and/or properties. They do this after having created a child binding context with a call to bindingContext.EnterNestedScope that loads the newly created child binding context in the same bindingContext variable. The call is enclosed within an using block, so that the original bindingContext is restored after exiting the block.

As an example we will build a custom model binder for interfaces, that is, a model binder that binds interfaces by looking for a an implementation in the Asp.net core Dependency Injection framework, and then by calling back the binding process itself on that implementation. Interfaces model binding is not only a good example of recursive model binding but also an useful programming tool for the following reasons:

  1. Using interfaces instead of concrete ViewModels allows a better separation between business layer and user interface layer.
  2. ViewModels inheritance allows a better reuse of views and metadata (validation attributes, DisplayAttributes, etc.), and interfaces overcome the limitation of inheriting from a single father class, since each interface may inherit from multiple other interfaces.

Asp.net core Mvc already has a model binder that is able to inject objects from the Dependency Injection engine into action methods. Its usage is triggered by the FromServicesAttribute, and it just injects object instances as they are returned by the DI engine without binding their properties to the input received by the client. Our custom model binder, instead, will be invoked only on interfaces or abstract classes and only when no FromServicesAttribute is provided. Moreover, once invoked it will bind all interface/abstract class properties against the input received by the client.

Preparing the project

As a first step let create a new asp.net core project named “ModelBindingInterfaces” and let select “no authentication”. Then let create a new folder called “ViewModels”.

Now let add an Interface called “ITestInterface”  to this folder :

using System.ComponentModel.DataAnnotations;

namespace ModelBindingInterfaces.ViewModels
{
    public interface ITestInterface
    {
        [Range(1, 10)]
        int TestProperty { get; set; }
    }
}

and a class implementing this interface, called “TestViewModel”:

using Microsoft.AspNetCore.Mvc;

namespace ModelBindingInterfaces.ViewModels
{
    [ModelMetadataType(typeof(ITestInterface))]
    public class TestViewModel : ITestInterface
    {
        public int TestProperty { get; set; }
    }
}

All metadata are added to the interface, so, to be sure they are used also by its implementation, we define the interface as a “ModelMetaDataType” for its implementation.

Now let register the above pair in the dependency injection engine, by adding the last line of the code below to the “startup.cs” file:

public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddApplicationInsightsTelemetry(Configuration);
            services.AddTransient<ITestInterface, TestViewModel>();

Finally, we need a controller and a test view. Let modify the “Index” action method of the HomeController in “HomeController.cs” as follows:

public IActionResult Index()
{
    return View();
}
[HttpPost]
public IActionResult Index(ITestInterface model)
{
    return View(model);
}

 

And also its “Views\Home\Index.cshtml” associated view:

@model ModelBindingInterfaces.ViewModels.ITestInterface

@{
    ViewData["Title"] = "Model Binding Interfaces";
}

<h2>@ViewData["Title"]</h2>

<form asp-action="Index" asp-controller="Home">
    <div class="form-group">
        <label asp-for="TestProperty" class="control-label"></label>
        <input asp-for="TestProperty" class="form-control">
        <span asp-validation-for="TestProperty" class="text-danger"></span>
    </div>
    <button type="submit" class="btn btn-default">Submit</button>
</form>

 

As you can see both controller and view reference only the interface. The only chunk of code that mentions its actual implementation is the DI container definition.

If you run the project as it is now, and try to submit the Index form, you get the following error:

“ModelBindingInterfaces.ViewModels.ITestInterface' does not have a default constructor”

In fact, all default model binders are not able to create automatically an instance of the  “ITestInterface'” interface.

Implementing the custom model binder

Our model binder should perform a job similar to the one of the built-in ComplexTypeModelBinder. The only difference being that instead of attempting to create an interface it should invoke the the DI engine to get an instance of a class that implements the interface. The code of the ComplexTypeModelBinder is quite complex, but its kernel is the invocation of “bindingContext.EnterNestedScope” on each type property. EnterNestedScope is passed an updated "ModelName" obtained by appending ".<property name>" to the current ModelName. ModelName is used to retrieve data from the input received by the client once a leaf property is reached, as we have seen in the previous post of this series. Inside the using block associated to EnterNestedScope there is a call to the “BindProperty” method, that in turn, retrieves the right binder for the property by looking in the dictionary of all property binders that is passed in the ComplexTypeModelBinder constructor. Once the right binder is found it is invoked on the child binding context created by “bindingContext.EnterNestedScope”. The result is finally stored in a variable defined outside the using block.

All results returned by the recursive calls on all  properties are then used to populate an instance of the type created by the “CreateModel” method.

We need just to modify “CreateModel” so that it uses the DI engine to get an instance of the type. Thus, we may inherit from the ComplexTypeModelBinder  and override its CreateModel method.

Let add the new “ModelBinders” folder to our project, and then add our “InterfacesModelBinder” class to this folder:

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;

namespace ModelBindingInterfaces.ModelBinders
{
    public class InterfacesModelBinder : ComplexTypeModelBinder
    {

        public InterfacesModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinder)
            : base(propertyBinder)
        {

        }
        protected override object CreateModel(ModelBindingContext bindingContext)
        {
            return bindingContext.HttpContext
                .RequestServices.GetService(bindingContext.ModelType);
        }
    }
}

 

Implementing the provider

In the previous post of the series we have seen that model binders are selected and created by model binder providers, so now it is time to write a provider for our custom model binder. Before start coding we need an answer to two questions:

  1. When the provider must return a not null result, meaning when we are in the right situation when our custom model binder must be used.
  2. Which parameters to pass in the constructor of the model binder.

The right conditions for using our “InterfacesModelBinder” are:

  • we are going to bind either an interface or an abstract class
  • the interface is not an IEnumerable, otherwise the built-in CollectionModelBinder/DictionaryModelBinder would be more appropriate
  • no FromServicesAttribute is in place, since this attribute is used when the user needs just the injection of a type with no subsequent binding of the type against the input provided by the client.

Finally, the constructor of our “InterfacesModelBinder” needs a dictionary whose entries associate the right binder to each type property.

Now we have all information to add our InterfacesModelBinderProvider class to the ModelBinders folder:

using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace ModelBindingInterfaces.ModelBinders
{
    public class InterfacesModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (!context.Metadata.IsCollectionType &&
                (context.Metadata.ModelType.GetTypeInfo().IsInterface ||
                 context.Metadata.ModelType.GetTypeInfo().IsAbstract)  &&
                (context.BindingInfo.BindingSource == null ||
                !context.BindingInfo.BindingSource
                .CanAcceptDataFrom(BindingSource.Services)))
            {
                var propertyBinders = new Dictionary<ModelMetadata, IModelBinder>();
                for (var i = 0; i < context.Metadata.Properties.Count; i++)
                {
                    var property = context.Metadata.Properties[i];
                    propertyBinders.Add(property, context.CreateBinder(property));
                }
                return new InterfacesModelBinder(propertyBinders);
            }

            return null;
        }
    }
}

The metadata of each property are taken from the MetaData.Properties array contained in the context object passed to the GetBinder method of the provider. Then, a binder for the property is created by invoking the CreateBinder method of the same context object on the property metadata.The remainder of the code is self-explicative.

The provider is installed with the same procedure of our previous post. Go to the startup.cs file and modify the ConfigureServices method as shown below:

public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddApplicationInsightsTelemetry(Configuration);
            services.AddTransient<ITestInterface, TestViewModel>();
            services.AddMvc(o =>
            {
                o.ModelBinderProviders.Insert(0,
                    new ModelBinders.InterfacesModelBinderProvider());
            });

As in our previous post, our provider is inserted at the top of the list of all providers to avoid that some other built-in provider might return a different model binder also when all conditions for the application of our InterfacesModelBinder are satisfied.

We have Finished! Run the project and verify how the interface is bound properly, and also how validation errors work properly.

Our series on model binding ended

but stay tuned!

We are preparing new enjoying adventures!

Francesco

Tags: , ,