"ASP. NET Core" from submitting plain text content to the Web API

Source: Internet
Author: User
Tags processing text



In the past few days, the old week in upgrading the "South China Leisure Kidney Recovery Registration Platform", in order to expand the business, in particular, allow other developers to the system to submit information about the kidney, so that the system added several Web APIs.



Among them, the introduction of the kidney is submitted in plain text, the approximate code is this.


[Route("api/[controller]/[action]")]
     Public class PigController : Controller
     {
         [HttpPost]
         Public string KidneyRemarks([FromBody]string remarks)
         {
             Return $"According to your description, the current state of your kidney is: {remarks}";
         }
     }


This Action is very simple (mainly for the convenience of others to understand), the parameter accepts a string instance, the return is also a string. Oh, the point to remember is to add the Frombody attribute to the parameter. Well, why? Because the data we're going to get is extracted from the HTTP body sent from the client, this feature means that the value of the parameter comes from the body of the submission, not the Header, not the URL parameter.



Then the old weeks were happily tested with Postman.



Fantasy is always beautiful, the reality is always very skinny. Results......









No success, at this time, according to conventional ideas, will produce various doubts. Did you suspect the address was wrong? Which configuration is not written? Is the route not correct? ......



Don't worry, look at the status code returned by the server: 415 unsupported Media Type. What do you mean, actually, that's the problem. We submit plain text type of data, with the Content-type is Text/plain, but, not supported!



Don't believe me? Now change the content of the submission to JSON.






Look, I'm not wrong about it.



This is clear, JSON is supported by default, but plain text is not. Is there a way to make it support the Text/plain type of data? The answer is: yes.



When configuring a service using the Configureservices method in Startup, we generally simply write.


   Services. Addmvc ();


Then, the individual MVC options remain the default.



In the MVC option, you can control the format of the input and output, which is managed by two properties, respectively:



Inputformatters Property: is a collection in which each object implements the Iinputformatter interface, which provides support for JSON and XML by default.



Outputformatters Property: is also a collection, the elements inside to implement the Ioutputformatter interface, the default support JSON and XML, also supports text types.



That is, the output supports plain text, so the Action can return a value of type string, but the input is not supported in text format, so you will get 415 code if you submit it in text/plain format.






Understand this principle, solve the problem to be done, we have to implement a inputformatter to support the plain text format is OK. However, we do not have to directly implement the Iinputformatter interface, because there is an abstract class very good--textinputformatter, processing text directly implement it.



So, the old week wrote this class.


Public sealed class PlainTextInputFormatter : TextInputFormatter
     {
         Public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
         {
             String content;
             Using(var reader = context.ReaderFactory(context.HttpContext.Request.Body, encoding))
             {
                 Content = await reader.ReadToEndAsync();
             }
             // Don't forget the last step
             Return await InputFormatterResult.SuccessAsync(content);
         }
     }


Only the Readrequestbodyasync method of the Textinputformatter class is abstract, so if there is no other job to do, it is enough to implement this method. The function of this method is to read the body of the HTTP request and then populate the Inputformatterresult object with what you read.



Inputformatterresult class is interesting, there is no public constructor, you can not new objects, only rely on the matchmaker to introduce objects, through Failure, Success these methods directly return object instances. These methods you know what the use of the name, do not have to explain more.



In the above code, the Readerfactory property is actually a delegate, created by the constructor, but the delegate instance is created when it is passed into the Readrequestbodyasync method, you just need to invoke it just like the method called, the first argument is a stream, Where's the flow? Of course, the body of the HTTP request, which can be obtained through the body of the HttpContext requests, the second parameter, oh, is the text encoding, this good to do, directly into the Readrequestbodyasync method of encoding pass the past on the line The



Readerfactory returns a TextReader after a delegate invocation, which is what we use to read the request body. Finally, the read-out string is filled to inputformatterresult.



However, this class is not available now, because by default, the Supportedmediatypes collection is empty, you have to add it, it supports which content-type, we just need to text/plain on the line.


    public PlainTextInputFormatter()
        {
            SupportedMediaTypes.Add("text/plain");
            SupportedEncodings.Add(System.Text.Encoding.UTF8);
        }


These are written in the constructor and are OK. Note Supportedencodings Collection, is the configuration character encoding, generally, UTF-8 most suitable. You can also get from two read-only static fields of the Textinputformatter class.


 
protected static readonly Encoding UTF8EncodingWithoutBOM; 
protected static readonly Encoding UTF16EncodingLittleEndian;


Now it's almost ready to use. Because the action we wrote above is a string type parameter, if you feel uncomfortable, you can override the Canreadtype method, this method has a type parameter, refers to the Model type, white is the Action to receive the type of parameters, we here is St Ring, so, implementing this method is simple, if the string type returns True, indicating that it can read, otherwise returns false, indicating that it cannot be read.






Back to the Startup class, find the Configureservices method, we addmvc in the time to configure the Options, we have just written inputformatter add in.


    public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(opt => {  opt.InputFormatters.Add(new PlainTextInputFormatter());  });
        }


OK, now please Postman uncle, re-test.









Well, everybody is happy and we have a problem to solve.






We might as well continue to expand if the Text/plain data content is being submitted, and the Action wants to assign it to a parameter of DateTime or int type. In fact, the same is the realization of their own input format. This time we do not inherit the Textinputformatter class, but instead inherit the Inputformatter class with a higher degree of abstraction.


  public sealed class CustInputFormatter : InputFormatter
    { public CustInputFormatter()
        {
            SupportedMediaTypes.Add("text/plain");
        } protected override bool CanReadType(Type type)
        { return (type == typeof(DateTime)) || (type == typeof(int));
        } public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
        { string val; using (var reader = context.ReaderFactory(context.HttpContext.Request.Body, Encoding.UTF8))
            {
                val = await reader.ReadToEndAsync();
            }
            InputFormatterResult result = null; if(context.ModelType == typeof(DateTime))
            {
                result = InputFormatterResult.Success(DateTime.Parse(val));
            } else {
                result = InputFormatterResult.Success(int.Parse(val));
            } return result;
        }
    }


This time I should not explain, you can read it. Note, however, that the target parameter to be applied might be an int and a DateTime type, so when you populate the Inputformatterresult object, you need to check the Modeltype property first.


   if(context.ModelType == typeof(DateTime))
            {
                result = InputFormatterResult.Success(DateTime.Parse(val));
            } else {
                result = InputFormatterResult.Success(int.Parse(val));
            }


Now apply this input format class.


  public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(o => {
                o.InputFormatters.Add(new CustInputFormatter());
            });
        }



Let's try it, build a Controller, then define two actions, a parameter that receives an int type, and a parameter that receives a DateTime type.


[Route("[controller]/[action]")]
     Public class TestController : Controller
     {
         [HttpPost]
         Public string Upload([FromBody]DateTime dt)
         {
             Return $"The time you submitted is: {dt}";
         }

         [HttpPost]
         Public string UploadInt([FromBody]int val)
         {
             Return $"The integer value you submitted is: {val}";
         }
     } 


Frombody characteristics must remember to use, otherwise you will not be able to read and Debug everywhere.






OK, the test begins, first try the DateTime type.









Try the int type again.









How do you feel, so exciting. Well, today's high-skill is shared here.



Sample source code Download: Please use the force of the primitive.






"ASP. NET Core" from submitting plain text content to the Web API


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.