{"id":24,"date":"2024-12-04T16:03:22","date_gmt":"2024-12-04T16:03:22","guid":{"rendered":"https:\/\/programming.rexthestrange.com\/?p=24"},"modified":"2024-12-04T16:03:22","modified_gmt":"2024-12-04T16:03:22","slug":"model-binding","status":"publish","type":"post","link":"https:\/\/programming.rexthestrange.com\/?p=24","title":{"rendered":"Model Binding"},"content":{"rendered":"\n<p>There are a plethora of examples for model binding and, like most examples, they are run through the complicator. So here is the short version.<\/p>\n\n\n\n<p>Model binding is the idea of taking the data that is passed into an API call and massaging it into a form that is expected by the API handler. This is usually done by default. If you have a handler function like this one:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;HttpPost]\n&#91;Route (\"someroute\")]\npublic IActionResult some_function (SomeType parameters) {\n\t...\n}<\/code><\/pre>\n\n\n\n<p>And let&#8217;s assume SomeType takes the form:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class SomeType {\n\tpublic String some_string { get; set; }\n\tpublic int some_int { get; set; }\n}<\/code><\/pre>\n\n\n\n<p>And you pass in the following query string:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>?some_string=mystringthing&amp;some_int=57<\/code><\/pre>\n\n\n\n<p>Then the default model binder will take that query string, break it into its component parts, create a SomeType instance and assign those values to the various properties which it then passes to the handler.<\/p>\n\n\n\n<p>Now, let&#8217;s assume that there&#8217;s a third property in SomeType:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class SomeType {\n\tpublic String some_string { get; set; }\n\tpublic int some_int { get; set; }\n\tpublic String another_string { get; set; }\n}<\/code><\/pre>\n\n\n\n<p>And, whenever this isn&#8217;t provided, you want to add:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>some_type.another_string = \"default another string\"<\/code><\/pre>\n\n\n\n<p>You could simply add this line in your API handler function, but what if you want to do that for every API handler function? That&#8217;s where the custom binder comes into play.<\/p>\n\n\n\n<p>There are three steps:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Create the binder class\/function.<\/li>\n\n\n\n<li>Create a &#8220;provider&#8221;.<\/li>\n\n\n\n<li>Register the provider.<\/li>\n<\/ol>\n\n\n\n<p>The binder class\/function is the one that everyone seems to overcomplicate. It&#8217;s really very simple. It implements the IModelBinder interface and defines a BindModelAsync function. In the BindModelAsync function it passes a new object to ModelBindingResult.Success function, assigns the output to ModelBindingContext.Result and returns Task.CompletedTask (saying everything is okay). It looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class &#91;CustomBinder - chose your own name]: IModelBinder {\n\n\tpublic Task BindModelAsync (ModelBindingContext context) {\n\t\tSomeType new_object = &#91;Create your new object here, for example:];\n\t\tnew_object.another_string = \"Yay!\";\n\t\tcontext.Result = ModelBindingResult.Success (new_object);\n\t\treturn Task.CompletedTask;\n\t}\/\/ BindModelAsync;\n}\/\/ CustomBinder;<\/code><\/pre>\n\n\n\n<p>Easy, no? Here you can do whatever you need to shape your SomeType instance into whatever you like.<\/p>\n\n\n\n<p>Step 2: Create a Provider.<\/p>\n\n\n\n<p>This is a class that implements the IModelBinderProvider interface, and simply says: hey, I have a new binder. This is what it is. And it looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class BinderProvider: IModelBinderProvider {\n\n\tpublic IModelBinder? GetBinder (ModelBinderProviderContext context) {\n\t\tArgumentNullException.ThrowIfNull (context);\n\t\treturn new BinderTypeModelBinder (typeof (CustomBinder));\n\t}\/\/ GetBinder;\n\n}\/\/ BinderProvider;<\/code><\/pre>\n\n\n\n<p>The first line of the GetBinder method checks to make sure that a context (the nuts and bolts of the binder) actually exists and throws an exception if it doesn&#8217;t. The second line simply returns a new instance of our custom binder.<\/p>\n\n\n\n<p>Step 3: Register the provider<\/p>\n\n\n\n<p>In your program.cs file (this is for .Net Core &#8211; MVC has its own arrangement, which I don&#8217;t plan on going into), add the provider when you add controllers. You might have something like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>WebApplicationBuilder builder = WebApplication.CreateBuilder (args);\n\nbuilder.Services.AddControllers ();<\/code><\/pre>\n\n\n\n<p>Just modify the AddControllers method to add an arrow function to insert the custom binder into the binder chain (yes, you can have multiple custom binders), like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>builder.Services.AddControllers (options => options.ModelBinderProviders.Insert (0, new BinderProvider ())).AddNewtonsoftJson ();<\/code><\/pre>\n\n\n\n<p>This will insert our binder at the root (position 0) of the providers list.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>What you see here is the bare minimum to create a custom binder. Also, in the binder method you can get the original query string by accessing:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>context.HttpContext.Request.Body<\/code><\/pre>\n\n\n\n<p>And reading it with a stream reader. Google it. Again, plenty of examples.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are a plethora of examples for model binding and, like most examples, they are run through the complicator. So here is the short version. Model binding is the idea of taking the data that is passed into an API call and massaging it into a form that is expected by the API handler. This [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-24","post","type-post","status-publish","format-standard","hentry","category-c-net"],"_links":{"self":[{"href":"https:\/\/programming.rexthestrange.com\/index.php?rest_route=\/wp\/v2\/posts\/24","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/programming.rexthestrange.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/programming.rexthestrange.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/programming.rexthestrange.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/programming.rexthestrange.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=24"}],"version-history":[{"count":1,"href":"https:\/\/programming.rexthestrange.com\/index.php?rest_route=\/wp\/v2\/posts\/24\/revisions"}],"predecessor-version":[{"id":25,"href":"https:\/\/programming.rexthestrange.com\/index.php?rest_route=\/wp\/v2\/posts\/24\/revisions\/25"}],"wp:attachment":[{"href":"https:\/\/programming.rexthestrange.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=24"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/programming.rexthestrange.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=24"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/programming.rexthestrange.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=24"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}