{"action":"created","issue":{"url":"https://api.github.com/repos/aspnet/Mvc/issues/4703","repository_url":"https://api.github.com/repos/aspnet/Mvc","labels_url":"https://api.github.com/repos/aspnet/Mvc/issues/4703/labels{/name}","comments_url":"https://api.github.com/repos/aspnet/Mvc/issues/4703/comments","events_url":"https://api.github.com/repos/aspnet/Mvc/issues/4703/events","html_url":"https://github.com/aspnet/Mvc/issues/4703","id":156087373,"number":4703,"title":"Asp net core rc2. Abstract class model binding","user":{"login":"AR1ES","id":5893853,"avatar_url":"https://avatars.githubusercontent.com/u/5893853?v=3","gravatar_id":"","url":"https://api.github.com/users/AR1ES","html_url":"https://github.com/AR1ES","followers_url":"https://api.github.com/users/AR1ES/followers","following_url":"https://api.github.com/users/AR1ES/following{/other_user}","gists_url":"https://api.github.com/users/AR1ES/gists{/gist_id}","starred_url":"https://api.github.com/users/AR1ES/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AR1ES/subscriptions","organizations_url":"https://api.github.com/users/AR1ES/orgs","repos_url":"https://api.github.com/users/AR1ES/repos","events_url":"https://api.github.com/users/AR1ES/events{/privacy}","received_events_url":"https://api.github.com/users/AR1ES/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/aspnet/Mvc/labels/question","name":"question","color":"cc317c"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/aspnet/Mvc/milestones/18","html_url":"https://github.com/aspnet/Mvc/milestones/Discussions","labels_url":"https://api.github.com/repos/aspnet/Mvc/milestones/18/labels","id":1254581,"number":18,"title":"Discussions","description":"","creator":{"login":"Eilon","id":202643,"avatar_url":"https://avatars.githubusercontent.com/u/202643?v=3","gravatar_id":"","url":"https://api.github.com/users/Eilon","html_url":"https://github.com/Eilon","followers_url":"https://api.github.com/users/Eilon/followers","following_url":"https://api.github.com/users/Eilon/following{/other_user}","gists_url":"https://api.github.com/users/Eilon/gists{/gist_id}","starred_url":"https://api.github.com/users/Eilon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Eilon/subscriptions","organizations_url":"https://api.github.com/users/Eilon/orgs","repos_url":"https://api.github.com/users/Eilon/repos","events_url":"https://api.github.com/users/Eilon/events{/privacy}","received_events_url":"https://api.github.com/users/Eilon/received_events","type":"User","site_admin":false},"open_issues":30,"closed_issues":2,"state":"open","created_at":"2015-08-14T02:04:42Z","updated_at":"2016-05-27T19:31:45Z","due_on":null,"closed_at":null},"comments":6,"created_at":"2016-05-21T06:38:31Z","updated_at":"2016-05-30T18:22:58Z","closed_at":null,"body":"Following this StackOverflow post:\r\nhttp://stackoverflow.com/questions/37318029/asp-net-core-rc2-abstract-class-model-binding\r\n\r\nIn the RC1 I use the following code for abstract classes or interfaces binding:\r\n\r\n\tpublic class MessageModelBinder : IModelBinder {\r\n\r\n\t\tpublic Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext) {\r\n\t\t\tif(bindingContext.ModelType == typeof(ICommand)) {\r\n\t\t\t\tvar msgTypeResult = bindingContext.ValueProvider.GetValue(\"messageType\");\r\n\t\t\t\tif(msgTypeResult == ValueProviderResult.None) {\r\n\t\t\t\t\treturn ModelBindingResult.FailedAsync(bindingContext.ModelName);\r\n\t\t\t\t}\r\n\t\t\t\tvar type = Assembly.GetAssembly(typeof(MessageModelBinder )).GetTypes().SingleOrDefault(t => t.FullName == msgTypeResult.FirstValue);\r\n\t\t\t\tif(type == null) {\r\n\t\t\t\t\treturn ModelBindingResult.FailedAsync(bindingContext.ModelName);\r\n\t\t\t\t}\r\n\t\t\t\tvar metadataProvider = (IModelMetadataProvider)bindingContext.OperationBindingContext.HttpContext.RequestServices.GetService(typeof(IModelMetadataProvider));\r\n\t\t\t\tbindingContext.ModelMetadata = metadataProvider.GetMetadataForType(type);\r\n\t\t\t}\r\n\t\t\treturn ModelBindingResult.NoResultAsync;\r\n\t\t}\r\n\t}\r\n\r\nThis binder only reads model type (`messageType` parameter) from query string and overrides metadata type. And the rest of the work performed by standard binders such as `BodyModelBinder`.\r\n\r\nIn Startup.cs I just add first binder:\r\n\r\n    services.AddMvc().Services.Configure<MvcOptions>(options => {\r\n\t\toptions.ModelBinders.Insert(0, new MessageModelBinder());\r\n\t});\r\n\r\nController:\r\n\r\n    [Route(\"api/[controller]\")]\r\n    public class MessageController : Controller {\r\n        [HttpPost(\"{messageType}\")]\r\n        public ActionResult Post(string messageType, [FromBody]ICommand message) {\r\n        } \r\n    }\r\n\r\nHow can I perform this in RC2?\r\n\r\nAs far as I understand, now I have to use `IModelBinderProvider`. OK, I tried.\r\nStartup.cs:\r\n\r\n    services.AddMvc().Services.Configure<MvcOptions>(options => {\r\n\t\toptions.ModelBinderProviders.Insert(0, new MessageModelBinderProvider());\r\n\t});\r\n\r\nModelBinderProvider:\r\n\r\n    public class MessageModelBinderProvider : IModelBinderProvider {\r\n\t\tpublic IModelBinder GetBinder(ModelBinderProviderContext context) {\r\n\t\t\tif(context == null) {\r\n\t\t\t\tthrow new ArgumentNullException(nameof(context));\r\n\t\t\t}\r\n\t\t\treturn context.Metadata.ModelType == typeof(ICommand) ? new MessageModelBinder() : null;\r\n\t\t}\r\n\t}\r\n\r\nModelBinder:\r\n\r\n\tpublic class MessageModelBinder : IModelBinder {\r\n\t\tpublic Task BindModelAsync(ModelBindingContext bindingContext) {\r\n\t\t\tif(bindingContext.ModelType == typeof(ICommand)) {\r\n\t\t\t\tvar msgTypeResult = bindingContext.ValueProvider.GetValue(\"messageType\");\r\n\t\t\t\tif(msgTypeResult == ValueProviderResult.None) {\r\n\t\t\t\t\tbindingContext.Result = ModelBindingResult.Failed(bindingContext.ModelName);\r\n\t\t\t\t\treturn Task.FromResult(0);\r\n\t\t\t\t}\r\n\t\t\t\tvar type = typeof(MessageModelBinder).GetTypeInfo().Assembly.GetTypes().SingleOrDefault(t => t.FullName == msgTypeResult.FirstValue);\r\n\t\t\t\tif(type == null) {\r\n\t\t\t\t\tbindingContext.Result = ModelBindingResult.Failed(bindingContext.ModelName);\r\n\t\t\t\t\treturn Task.FromResult(0);\r\n\t\t\t\t}\r\n\t\t\t\tvar metadataProvider = (IModelMetadataProvider)bindingContext.OperationBindingContext.HttpContext.RequestServices.GetService(typeof(IModelMetadataProvider));\r\n\t\t\t\tbindingContext.ModelMetadata = metadataProvider.GetMetadataForType(type);\r\n\t\t\t\tbindingContext.Result = ModelBindingResult.Success(bindingContext.ModelName, Activator.CreateInstance(type));\r\n\t\t\t}\r\n\t\t\treturn Task.FromResult(0);\r\n\t\t}\r\n\t}\r\n\r\nBut I cannot specify `NoResult`. If I do not specify `bindingContext.Result`, I get null model in controller.\r\nIf I specify `bindingContext.Result`, I get empty model without setting model fields."},"comment":{"url":"https://api.github.com/repos/aspnet/Mvc/issues/comments/222537600","html_url":"https://github.com/aspnet/Mvc/issues/4703#issuecomment-222537600","issue_url":"https://api.github.com/repos/aspnet/Mvc/issues/4703","id":222537600,"user":{"login":"dougbu","id":6431421,"avatar_url":"https://avatars.githubusercontent.com/u/6431421?v=3","gravatar_id":"","url":"https://api.github.com/users/dougbu","html_url":"https://github.com/dougbu","followers_url":"https://api.github.com/users/dougbu/followers","following_url":"https://api.github.com/users/dougbu/following{/other_user}","gists_url":"https://api.github.com/users/dougbu/gists{/gist_id}","starred_url":"https://api.github.com/users/dougbu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dougbu/subscriptions","organizations_url":"https://api.github.com/users/dougbu/orgs","repos_url":"https://api.github.com/users/dougbu/repos","events_url":"https://api.github.com/users/dougbu/events{/privacy}","received_events_url":"https://api.github.com/users/dougbu/received_events","type":"User","site_admin":false},"created_at":"2016-05-30T18:22:58Z","updated_at":"2016-05-30T18:22:58Z","body":"One issue in the binder just above: I should have saved `bindingContext.Result` and restored it after the `using`. That means the `BindModelAsync()` method must be `async`."}}
{"actor":{"display_login":"dougbu"}}