{"id":5529,"date":"2018-09-23T13:00:26","date_gmt":"2018-09-23T13:00:26","guid":{"rendered":"http:\/\/writeasync.net\/?p=5529"},"modified":"2018-09-22T19:24:36","modified_gmt":"2018-09-22T19:24:36","slug":"find-the-issue-parameter-types","status":"publish","type":"post","link":"http:\/\/writeasync.net\/?p=5529","title":{"rendered":"Find the issue: parameter types"},"content":{"rendered":"<p>Can you find the issue in this <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/web-api\/overview\/getting-started-with-aspnet-web-api\/tutorial-your-first-web-api\">ASP.NET Web API<\/a> code snippet?<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic sealed class MyCommandController : ApiController\r\n{\r\n    public string Post(string useTheForce, string timeout, string auditMessage)\r\n    {\r\n        Process myCommand = Process.Start(\r\n            &quot;MyCommand.exe&quot;,\r\n            $&quot;-useTheForce {useTheForce} -timeout {timeout} -auditMessage {auditMessage}&quot;);\r\n        myCommand.WaitForExit();\r\n        return $&quot;Completed with exit code {myCommand.ExitCode}&quot;;\r\n    }\r\n}\r\n<\/pre>\n<p>I admit that this is sort of a trick question because there is certainly more than one issue. But let&#8217;s start today with the <code>Post()<\/code> method signature.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ . . .\r\npublic string Post(\r\n    string useTheForce,\r\n    string timeout,\r\n    string auditMessage)\r\n\/\/ . . .\r\n<\/pre>\n<p>Judging by their use as inputs to <code>MyCommand.exe<\/code>, the parameters <code>useTheForce<\/code> and <code>timeout<\/code> expect a Boolean and an integer value, respectively. Yet, they are passed as strings. We have a classic case of <a href=\"http:\/\/wiki.c2.com\/?StringlyTyped\">stringly-typed<\/a> code!<\/p>\n<p>Luckily <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/web-api\/overview\/formats-and-model-binding\/parameter-binding-in-aspnet-web-api\">parameter binding in Web API<\/a> is very easy for simple data types. So we can fix this by merely changing the parameter types:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic string Post(\r\n    bool useTheForce,\r\n    int timeout,\r\n    string auditMessage)\r\n\/\/ . . .\r\n<\/pre>\n<p>Not only is the intent of the code clearer but we also get basic parameter validation for free. For example, if you try to pass some value like &#8220;Yes&#8221; for <code>useTheForce<\/code> you get this error:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n{\r\n  &quot;Message&quot;: &quot;The request is invalid.&quot;,\r\n  &quot;MessageDetail&quot;: &quot;The parameters dictionary contains a null entry for parameter 'useTheForce' of non-nullable type 'System.Boolean' for method 'System.String Post(Boolean, Int32, System.String)' in 'SampleApp.MyCommandController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.&quot;\r\n}\r\n<\/pre>\n<p>It is convenient, yes, but those error details do leave something to be desired. That can be addressed a couple different ways. One option is to use a <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/web-api\/overview\/formats-and-model-binding\/model-validation-in-aspnet-web-api#handling-validation-errors\">custom ActionFilter for model validation<\/a>. For instance:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n    internal sealed class ValidateModelAttribute : ActionFilterAttribute\r\n    {\r\n        public override void OnActionExecuting(HttpActionContext actionContext)\r\n        {\r\n            if (!actionContext.ModelState.IsValid)\r\n            {\r\n                actionContext.Response =\r\n                    actionContext.Request.CreateErrorResponse(\r\n                        HttpStatusCode.BadRequest, &quot;The request is invalid.&quot;);\r\n            }\r\n        }\r\n    }\r\n\r\n    \/\/ register globally in Startup.Configuration:\r\n    internal sealed class Startup\r\n    {\r\n        public void Configuration(IAppBuilder appBuilder)\r\n        {\r\n            HttpConfiguration config = new HttpConfiguration();\r\n            \/\/ . . .\r\n            config.Filters.Add(new ValidateModelAttribute());\r\n            \/\/ . . .\r\n        }\r\n    }\r\n<\/pre>\n<p>Now the error response looks like this:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n{ &quot;Message&quot;: &quot;The request is invalid.&quot; }\r\n<\/pre>\n<p>That gets rid of the inscrutable programmer-ese, but it is now quite terse and doesn&#8217;t tell the user what actually went wrong. Let&#8217;s instead create a <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/web-api\/overview\/data\/using-web-api-with-entity-framework\/part-2#add-model-classes\">full-blown model class<\/a> to represent the inputs. The added benefit there is the ability to specify even more finely grained validations on the various data members. In this example, we might come up with the following:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n    using System.ComponentModel.DataAnnotations;\r\n\r\n    public sealed class MyCommandParameters\r\n    {\r\n        &#x5B;Required]\r\n        public bool useTheForce { get; set; }\r\n\r\n        &#x5B;Required]\r\n        &#x5B;Range(0, 300)]\r\n        public int timeout { get; set; }\r\n\r\n        &#x5B;Required]\r\n        public string auditMessage { get; set; }\r\n    }\r\n<\/pre>\n<p>In order to have the same parameter binding experience as before, we have named the properties in lowercase. To ensure the values can be passed as query string parameters, we also need to change the <code>Post<\/code> method signature as follows:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic string Post(\r\n    &#x5B;FromUri] MyCommandParameters p)\r\n<\/pre>\n<p>Finally, to get a more meaningful error message, we can change the <code>ValidateModelAttribute<\/code> method like so:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n        public override void OnActionExecuting(HttpActionContext actionContext)\r\n        {\r\n            if (!actionContext.ModelState.IsValid)\r\n            {\r\n                actionContext.Response =\r\n                    actionContext.Request.CreateErrorResponse(\r\n                        HttpStatusCode.BadRequest, actionContext.ModelState);\r\n            }\r\n        }\r\n<\/pre>\n<p>The user error experience is now much better:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\/\/ If the user passes a large value for the timeout:\r\n{\r\n  &quot;Message&quot;: &quot;The request is invalid.&quot;,\r\n  &quot;ModelState&quot;: { &quot;timeout&quot;: &#x5B; &quot;The field timeout must be between 0 and 300.&quot; ] }\r\n}\r\n\r\n\/\/ If the user passes 'Yes' for the Boolean:\r\n{\r\n  &quot;Message&quot;: &quot;The request is invalid.&quot;,\r\n  &quot;ModelState&quot;: { &quot;useTheForce&quot;: &#x5B; &quot;The value 'Yes' is not valid for useTheForce.&quot;, &quot;The useTheForce field is required.&quot; ] }\r\n}\r\n<\/pre>\n<p>With just a bit of extra work, we can smoothly go from stringly-typed to strongly-typed. Tune in next time when we look at even more issues in this code sample!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Can you find the issue in this ASP.NET Web API code snippet? public sealed class MyCommandController : ApiController { public string Post(string useTheForce, string timeout, string auditMessage) { Process myCommand = Process.Start( &quot;MyCommand.exe&quot;, $&quot;-useTheForce {useTheForce} -timeout {timeout} -auditMessage {auditMessage}&quot;); myCommand.WaitForExit();&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[91],"tags":[],"class_list":["post-5529","post","type-post","status-publish","format-standard","hentry","category-design"],"_links":{"self":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5529","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5529"}],"version-history":[{"count":1,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5529\/revisions"}],"predecessor-version":[{"id":5530,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/5529\/revisions\/5530"}],"wp:attachment":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5529"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5529"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5529"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}