While converting an existing ASP.NET MVC application to ASP.NET Core I noticed it was using a custom model binder. That made me wonder how I could achieve the same thing in ASP.NET Core.
In ASP.NET MVC a model binder had to implement the IModelBinder interface:
public class UsersViewModelBinder : IModelBinder | |
{ | |
private UsersViewModel _usersViewModel = new UsersViewModel(); | |
private User _user = new User(); | |
private readonly IIAMService _iamService; | |
public UsersViewModelBinder(IIAMService iamService) | |
{ | |
this._iamService = iamService; | |
} | |
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) | |
{ | |
if (bindingContext == null) | |
throw new ArgumentNullException("bindingContext"); | |
if (bindingContext.ValueProvider.GetValue("User.Id") != null) | |
_user.Id = Int32.Parse(bindingContext.ValueProvider.GetValue("User.Id").AttemptedValue); | |
else _user.Id = 0; | |
_user.Name = bindingContext.ValueProvider.GetValue("User.Name").AttemptedValue; | |
_user.Alternativename1 = bindingContext.ValueProvider.GetValue("User.Alternativename1").AttemptedValue; | |
_user.Alternativename2 = bindingContext.ValueProvider.GetValue("User.Alternativename2").AttemptedValue; | |
_user.Alternativename3 = null; | |
_user.Rrnhash = bindingContext.ValueProvider.GetValue("User.Rrnhash").AttemptedValue; | |
if (bindingContext.ValueProvider.GetValue("User.UsCreate") != null) | |
_user.UsCreate = bindingContext.ValueProvider.GetValue("User.UsCreate").AttemptedValue; | |
if (bindingContext.ValueProvider.GetValue("User.TsCreate") != null) | |
_user.TsCreate = DateTime.Parse(bindingContext.ValueProvider.GetValue("User.TsCreate").AttemptedValue); | |
_user.APIKey = bindingContext.ValueProvider.GetValue("User.APIKey").AttemptedValue; | |
_usersViewModel.User = _user; | |
return _usersViewModel; | |
} | |
} |
To use the model binder you had to let the ASP.NET MVC framework know the existence of the custom model binder. In the original codebase we were using Unity and we created a small extension method that allowed us to register the Modelbinder:
/// <summary> | |
/// Extension methods for Unity. | |
/// </summary> | |
public static class IUnityContainerExtensions | |
{ | |
/// <summary> | |
/// Registers the model binder. | |
/// </summary> | |
/// <typeparam name="TModelBinder">The type of the model binder.</typeparam> | |
/// <typeparam name="TModel">The type of the model.</typeparam> | |
/// <param name="container">The container.</param> | |
/// <returns></returns> | |
public static IUnityContainer RegisterModelBinder<TModelBinder, TModel>(this IUnityContainer container)where TModelBinder:IModelBinder | |
{ | |
return container.RegisterModelBinder<TModelBinder, TModel>(new TransientLifetimeManager()); | |
} | |
/// <summary> | |
/// Registers the model binder. | |
/// </summary> | |
/// <typeparam name="TModelBinder">The type of the model binder.</typeparam> | |
/// <typeparam name="TModel">The type of the model.</typeparam> | |
/// <param name="container">The container.</param> | |
/// <param name="lifetimeManager">The lifetime manager.</param> | |
/// <returns></returns> | |
public static IUnityContainer RegisterModelBinder<TModelBinder, TModel>(this IUnityContainer container,LifetimeManager lifetimeManager) where TModelBinder:IModelBinder | |
{ | |
UnityModelBinderProvider.ModelBinders.Add(typeof(TModel)); | |
container.RegisterType<IModelBinder, TModelBinder>(typeof(TModel).Name,lifetimeManager); | |
return container; | |
} | |
} |
That extension method allowed us to write the following code:
var container=new UnityContainer(); | |
container.RegisterModelBinder<UsersViewModelBinder, UsersViewModel>(); |
Let’s find out how to achieve the same result in ASP.NET Core…
In ASP.NET Core you should also implement a IModelBinder interface, although the contract is different(and async):
public class UsersViewModelBinder : IModelBinder | |
{ | |
private readonly IIAMService _iamService; | |
public UsersViewModelBinder(IIAMService iamService) | |
{ | |
this._iamService = iamService; | |
} | |
public Task BindModelAsync(ModelBindingContext bindingContext) | |
{ | |
if (bindingContext == null) | |
{ | |
throw new ArgumentNullException(nameof(bindingContext)); | |
} | |
var usersViewModel=new UsersViewModel(); | |
var user=new User(); | |
if (bindingContext.ValueProvider.GetValue("User.Id") != ValueProviderResult.None) | |
user.Id = Int32.Parse(bindingContext.ValueProvider.GetValue("User.Id").FirstValue); | |
else | |
user.Id = 0; | |
user.Name = bindingContext.ValueProvider.GetValue("User.Name").FirstValue; | |
user.Alternativename1 = bindingContext.ValueProvider.GetValue("User.Alternativename1").FirstValue; | |
user.Alternativename2 = bindingContext.ValueProvider.GetValue("User.Alternativename2").FirstValue; | |
usersViewModel.User = user; | |
bindingContext.Result = ModelBindingResult.Success(usersViewModel); | |
return Task.CompletedTask; | |
} | |
} |
To use this custom model binder you can either create a custom ModelBinderProvider or use the ModelBinder attribute:
[ModelBinder(BinderType = typeof(UsersViewModelBinder))] | |
public class UsersViewModel | |
{ | |
public User User { get; set; } | |
} |
More information: Custom Model Binding in ASP.NET Core
No comments:
Post a Comment