In the last rotten article, Lao Zhou introduced to you Produces Use of features , In this article, Lao Zhou will introduce another feature class :FormatFilterAttribute.

This feature can be regarded as Filter Waistcoat , Except from Attribute Outside class derivation , It's also achieved IFilterFactory Interface . The reason why it is a vest , Because IFilterFactory Interface requires type implementation CreateInstance Method to generate an object instance of the filter . in other words ,FormatFilterAttribute Class does not really do filtering code , Instead, create a FormatFilter Class .


How does this guy work

This feature class can be applied to class ( controller ) And methods ( In the controller Action) On , It allows the API The caller of takes the initiative to choose the format of the returned data . What kind of operation is this ?

If you used to ( I'm talking about the past , Because now many only support JSON Format ) I have worked on an open platform like Weibo API call , May still remember in URL Select return through parameters on XML still JSON. Such as this :

http://what.com/api/getlist?t=xml
http://what.com/api/getlist?t=json

Yes, of course , The premise is that you write API Support the specified format , If the caller specifies jpg, And you wrote API If you don't support it, you will report an error . How format names make ASP.NET Core Identify the to return Content-Type What about ? Don't worry. , Just look down and see .

Let's talk about it first. FormatFilter How to get features API In the format specified by the caller . There are two ways :

  1. Find a routing rule named “format” Key words of . It's like MVC In routing rules “controller”、"action" Same keyword . If “format” Keyword recognition json, Then return JSON Formatted data ; If you recognize xml Just go back to XML Formatted data .
  2. From the request URL Found a query string named “format” Field of , If its value is json Said to return to JSON Formatted data ; if xml Just go back to XML Formatted data . For other values , You have to customize the implementation .

It's best to deal with it through routing rules , First, this method is more flexible , Second, do not occupy URL Query string , So as not to URL Too long .

Just now, Lao Zhou said that routing rules can be used “format” Keyword to identify the format , Want to know why , We can see FormatFilter Source code of class (FormatFilter Feature is just a shell , Nothing to look at ).

    public virtual string? GetFormat(ActionContext context)
{
if (context.RouteData.Values.TryGetValue("format", out var obj))
{
// null and string.Empty are equivalent for route values.
var routeValue = Convert.ToString(obj, CultureInfo.InvariantCulture);
return string.IsNullOrEmpty(routeValue) ? null : routeValue;
} var query = context.HttpContext.Request.Query["format"];
if (query.Count > 0)
{
return query.ToString();
} return null;
}

It starts with RouteData Look in the dictionary to see if it is related to “format” Corresponding value , If there is , Just go back to ; without , I'll find it again URL Query whether there is “format” Field .

As you can see , stay FormatFilter Class , This GetFormat Method is declared as virtual Of , To put it bluntly , You can customize your search method , Maybe you're not looking for someone named “format” Key words of , But is called “type”. You just start FormatFilter Class derivation , And then rewrite GetFormat Method . Finally, write your own new FormatFilter Sign up to MVC Option Filters In the list .


Try it

The test data class used here is Book.

    public class Book
{
/// <summary>
/// Number
/// </summary>
public uint ID { get; set; }
/// <summary>
/// Title
/// </summary>
public string Title { get; set; }
/// <summary>
/// author
/// </summary>
public string Author { get; set; }
/// <summary>
/// Time of issue
/// </summary>
public DateTime PublishTime { get; set; }
}

We assume that Book Object represents the basic information of a book .

then , Let's get a controller .

    [Route("api/bkstore")]
[ApiController, FormatFilter]
public class BooksController : ControllerBase
{
[HttpGet("list/{format?}")]
public IEnumerable<Book> ListBooks() => new Book[]
{
new() {ID=5112, Title="C Language from entry to wrist cutting ", Author=" Old week ", PublishTime = new(2011,10,12)},
new() {ID=72543, Title=" Heroes in the sewer ", Author=" Old week ", PublishTime= new(2021,4,17)},
new() {ID=28565, Title=" Lunch box era ", Author=" Lao zhang ", PublishTime= new(2022,5,1)},
new() {ID=80251, Title=" A city man with a lot of money and a stupid brain ", Author=" Bald head strength ", PublishTime= new(2017,6,8)}
};
}

Books The controller applies FormatFilter characteristic , Make the operation methods in the whole controller support format Keyword to choose the data format . Called URL The format is as follows :

http://localhost/api/bkstore/list/json
http://localhost/api/bkstore/list/xml

“{format?}” There is a question mark in , Indicates that this routing parameter is optional , You can omit . If omitted ,ASP.NET Core The application will find the first matching item from the list of registered formats as the default format . for example ,MVC In the format list json、xml、audio/wav Equiform , When {format} After the parameter is omitted , The default choice is json.

stay Program.cs Add other codes in the document , Register at API Controller function , To be called AddXmlSerializerFormatters Method , Only in this way can return be supported XML Formatted data .

var builder = WebApplication.CreateBuilder(args);
// add to XML Format support requires calling AddXmlSerializerFormatters Method
builder.Services.AddControllers().AddXmlSerializerFormatters();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//================================================================
var app = builder.Build();
//================================================================
app.UseSwagger();
app.UseSwaggerUI(o =>
{
o.RoutePrefix = "";
o.SwaggerEndpoint("swagger/v1/swagger.json", "swg");
}); app.MapControllers(); app.Run();

In the above code , Called UseSwaggerUI Other methods , Make the project support Web API Test of , In this place, Lao Zhou has modified some default configurations .

app.UseSwaggerUI(o =>
{
o.RoutePrefix = "";
o.SwaggerEndpoint("swagger/v1/swagger.json", "swg");
});

RoutePrefix Property set access Swagger The path of the page , Default to /swagger Next , I change it to an empty string , It means that you can access , Mainly for the convenience of testing . Direct access http://localhost:xxx/ Just OK. Due to the default prefix /swagger Has been removed , therefore , Get a description API Of JSON The access path of the document should be manually set back to the default path /swagger/v1/swagger.json, Otherwise, it will not be found after running API Information .

because Swagger UI The test page of cannot be {format?} Identified as optional parameters , So you should explicitly add xxx/json or xxx/xml.

http://localhost:5228/api/bkstore/list/json
http://localhost:5228/api/bkstore/list/xml

use XML The result returned when formatting :

use JSON The result returned when formatting :


Add a format by yourself

json、xml yes ASP.NET Core Automatically registered format name , We can also add some formats by ourselves .

builder.Services.AddControllers()
.AddXmlSerializerFormatters()
.AddFormatterMappings(mappings =>
{
mappings.SetMediaTypeMappingForFormat("txtj", "text/json");
});

After calling AddControllers、AddXmlSerializerFormatters after , Homeopathic call AddFormatterMappings Method to add a format map . adopt SetMediaTypeMappingForFormat The method is called txtj The format and text/json relation . In this way , Want to make API return Content-Type by text/json The data of , Just visit like this :

http://localhost:5228/api/bkstore/list/txtj

Earlier, Lao Zhou sold a pass :ASP.NET Core How does the program recognize the corresponding format MIME ? This SetMediaTypeMappingForFormat Method call is the answer . It maintains a Key/Value aggregate ( Understand it as a dictionary ),key Is the name of the format ( This can be customized ), Such as xml、json,jpg etc. , Then there will be one MIME With the corresponding . image json --> application/json,xml --> application/xml、abc --> image/png such .

however , If added txt --> text/plain Mapping , Will fail .

builder.Services.AddControllers().AddXmlSerializerFormatters()
.AddFormatterMappings(mappings =>
{
mappings.SetMediaTypeMappingForFormat("txt", "text/plain");
});

The reason is not ASP.NET Core You are not allowed to do this , But the format does not match . Remember what Lao Zhou said in his last hydrology ,text/plain Default by StringOutputFormatter Class to handle , Only the return value string Method of type . And in our example ListBooks The method is to return a Book List of objects , Type mismatch .

therefore , If you want to map txt --> text/plain On , You need to customize one Formatter, Let it be Book The list becomes a string . This guy can try it by himself ( It's better not to customize this too much , Otherwise, there are arrays and classes , It's hard to do , You can consider Book Class ToString Method , It may be easier ), Lao Zhou then uses another example to illustrate , Because this example does not return an array , Only a single instance is returned , You can scan all public attributes with reflection , Then connect it into a string . Yes, of course , This practice has great limitations , There is no way to apply it to all types , Just for demonstration .

First define the data class we need , It's called Goods, It means a commodity ( Because Lao Zhou opened a grocery store , So use Goods class ).

    public class Goods
{
/// <summary>
/// goods ID
/// </summary>
public uint ID { get; set; }
/// <summary>
/// Commodity title
/// </summary>
public string Name { get; set; } = "none";
/// <summary>
/// The unit price
/// </summary>
public decimal Price { get; set; }
/// <summary>
/// remarks
/// </summary>
public string Remark { get; set; } = string.Empty;
}

next , Implement custom Formatter class , The function we need here is to splice the public attributes of the object into a string and return it to the client . So we don't need to realize it completely by ourselves IOutputFormatter Interface , Directly from TextOutputFormatter Class derivation is ok . This product is an abstract class , We need to do two things :

  1. In the constructor, add SupportedMediaTypes Add supported MIME type . What formats do you want it to be compatible with , Just say goodbye Add Just go in OK 了 . In this example, Lao Zhou only hopes it supports text/plain Format , So just add this . Then I have to SupportedEncodings Add supported character encodings to the list , Now it's commonly used UTF-8 Just fine , Reduce a lot of trouble .

  2. Realization WriteResponseBodyAsync Method , Convert the object to be processed into a string , And write back to the response flow .

    public class MyOutputFormatter : TextOutputFormatter
{
public MyOutputFormatter()
{
/*
* The following two lines must be included
*/
// Add supported MIME type
SupportedMediaTypes.Add("text/plain");
// Add supported character encoding
SupportedEncodings.Add(Encoding.UTF8);
} public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
// Get the object instance being processed
object obj = context.Object;
// Get the object's Type
Type objtype = context.ObjectType;
if (obj is null || objtype is null)
{
return;
}
// Find out the public properties
var props = objtype.GetProperties(BindingFlags.Public | BindingFlags.Instance);
StringBuilder strbf = new();
// Read it out one by one
foreach (var p in props)
{
strbf.Append($"{p.Name}=");
object val = p.GetValue(obj);
if (!(val is null))
{
strbf.Append(val);
}
strbf.AppendLine();
}
// Write response content
await context.HttpContext.Response.WriteAsync(strbf.ToString());
}
}

stay Program.cs In file , call AddControllers Method , Put what you just defined Formatter Instance added to OutputFormatters In the list .

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(opt =>
{
opt.OutputFormatters.Add(new MyOutputFormatter());
})
.AddXmlSerializerFormatters()
.AddFormatterMappings(mappings =>
{
mappings.SetMediaTypeMappingForFormat("txt", "text/plain");
});
……

Last , Let's go back and add an operation method to the controller class .

        [HttpGet("buy/{format?}")]
public Goods BuySomething() => new Goods
{
ID = 93257,
Name = " Women's backpack made of dinosaur skin ",
Price = 58888.03M,
Remark = " Live delivery , No production license is required , No certificate , No need for quality control , No after sales ; No return or exchange , If the goods have quality problems , Please destroy by yourself "
};

Then run the test ( visit http://localhost:xxxx/api/bkstore/buy/txt). Return results :

ID=93257
Name= Women's backpack made of dinosaur skin
Price=58888.03
Remark= Live delivery , No production license is required , No certificate , No need for quality control , No after sales ; No return or exchange , If the goods have quality problems , Please destroy by yourself

【ASP.NET Core】 Set up Web API Format of response data ——FormatFilter More related articles in the feature article

  1. angular4 and asp.net core 2 web api

    angular4 and asp.net core 2 web api This is a study note . angular 5 The official version is almost out , But it's mainly a performance upgrade . In my submission angular 4 It's very suitable for enterprises , It's like .net ...

  2. View of , Use ASP.NET Core establish Web API, Always for the first time

    ASP.NET Core brief introduction ASP.NET Core Is a cross platform high-performance open source framework , Used to generate cloud enabled and connect Internet New applications of . Use ASP.NET Core, You can : Generate Web Applications and services . Object association ...

  3. Use ASP.NET Core MVC establish Web API—— Content negotiation of response data ( 7、 ... and )

    Use ASP.NET Core MVC establish Web API Use ASP.NET Core MVC establish Web API( One ) Use ASP.NET Core MVC establish Web API( Two ) send ...

  4. 【ASP.NET Core】 Set up Web API The data format of the response ——Produces Characteristics

    The first article of spring , Today, Lao Zhou will talk about a very simple topic with all of you : How to set API The data format of the response . Say essence , Is to set the returned content MIME type (Content-Type head ). Yes, of course , We won't use it in HTTP tube ...

  5. Use angular4 and asp.net core 2 web api Do an exercise ( One )

    This is a study note . angular 5 The official version is almost out , But it's mainly a performance upgrade . In my submission angular 4 It's very suitable for enterprises , It's like .net equally . I use it windows 10 Installation tools : git for ...

  6. Use angular4 and asp.net core 2 web api Do an exercise ( Four )

    The first part : http://www.cnblogs.com/cgzl/p/7755801.html The second part : http://www.cnblogs.com/cgzl/p/7763397.html Third ...

  7. Use angular4 and asp.net core 2 web api Do an exercise ( Two ), This part is all about angular

    Last one : http://www.cnblogs.com/cgzl/p/7755801.html complete client.service.ts: import { Injectable } from '@an ...

  8. be based on ASP.NET Core establish Web API

    Use Visual Studio Create project . file -> newly build -> project , Choose to create ASP.NET Core Web Applications . be based on ASP.NET Core 2.0 , choice API, Authentication select ...

  9. ASP.NET Core Restful Web API Related resources index

    GraphQL Use ASP.NET Core Development GraphQL The server -- Preliminary knowledge ( On ) Use ASP.NET Core Development GraphQL The server -- Preliminary knowledge ( Next ) [ video ] Use ASP.NET C ...

  10. Use ASP.NET Core establish Web API And links sqlserver database

    establish Web API https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/first-web-api?view=aspnetcore-3.0& ...

Random recommendation

  1. CODEVS1643 Line segments cover 3[ greedy ]

    1643 Line segments cover 3    The time limit : 2 s    Space restriction : 256000 KB    Question level : gold Gold Answer key       Title Description  Description On a number axis there is n Bar segment , Now choose ...

  2. analysis ThreadLocal

    If you define a single instance of java bean, It has several properties , But one property is not thread safe , for instance HashMap. And it happens that you don't need to share this property in different threads , That is to say, this property has no cross thread meaning . Then I don't recommend it ...

  3. ThrottleAttribute

    /// <summary> /// Decorates any MVC route that needs to have client requests limited by time. ...

  4. 【CodeForces 489A】SwapSort

    topic Description In this problem your goal is to sort an array consisting of n integers in at most n sw ...

  5. Function.caller

    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/caller Nonstandard ...

  6. Android And TextView Component learning

    One . Based on learning 1.findViewById return View class , This class is all View The parent class of the component . 2. Children have more properties and methods than parents , But if the subclass cannot be found, go to the parent class 3.marquee: Huagai , Running lamp effect :orie ...

  7. shell practice -- Create accounts in batches

    #!/bin/bash #By spinestars #-- #cksum5 Bit acquisition method , There may be duplication #pd="user`head -200 /dev/urandom | cksum | h ...

  8. How to get oracle RAC 11g asm spfile S files

     Method 1 : [[email protected] ~]# su - grid [[email protected] ~]$ sqlplus / as sysasm SQL*Plus: Release 11.2.0.3.0 ...

  9. JavaSE( Ten ) Gather them together Set

    Today's article is about what we didn't understand before TreeSet The comparison between the two is very clear , Also understand its underlying implementation . I hope Bo you can give me some advice ! One .Set Interface 1.1.Set Collection Overview Set aggregate : It's like a jar , Programs can put multiple objects in turn “ ...

  10. GDB debugging qemu-kvm

    GDB debugging qemu-kvm The previous blog posts record some kvm Compile, install and use related packages , But I didn't go deep into the code . Only by looking at the relevant principles of the source code can we better understand kvm. but qemu-kvm A lot of code , For me, look directly at the source code harvest ...