Coder Social home page Coder Social logo

coreformatters's Introduction

.NET Core Custom Formatters

This repository used to contain custom formatters for pdf and excel. They are removed from main branch as the libraries are deprecated. Please check previous commits if you are interested in those.

.Net Core gives you some formatters out of the box. This official documentation link described them briefly,

https://docs.microsoft.com/en-us/aspnet/core/mvc/models/formatting

We have two abstract classes provided by the framework, InputFormmeter and OutputFormatter. Basically you would want to use these classes to make your own formatters. But there are other two abstract classes that extend from those two formatters. TextInputFormatter and TextOuputFormatter can work with response that are simple string representations of data formats.

When using the Yaml output formatter you would get the response (returned value of the controller's action) out of the current HttpContext and Serialize them into raw Yaml response text and send them back to the client. Pretty much same goes for the input formatter. In this case, you would Deserialize the Yaml content from the client's request and use them in a generic form. Another important thing is, you have to explicitly set media type header for these formatters. Doing that will activate these formatters whenever a client defines a Accept header (for output) and Content-Type (for input) with that specific media type format (application/x-yaml).

If you don’t want to use those headers while calling your controller’s actions you can explicitly define the type of formatter that should be used while getting or posting content. For example, the [Produces(application/x-yaml)] will return the response in Yaml format whether you define a Accept header or not. Again using the [Consumes(application/x-yaml)] attribute would only accept Yaml content whether you define the Content-Type or not.

Yaml Output Formatter

public class YamlOutputFormatter : TextOutputFormatter
{
  private readonly Serializer _serializer;

  public YamlOutputFormatter(Serializer serializer)
  {
    _serializer = serializer;

    SupportedEncodings.Add(Encoding.UTF8);
    SupportedEncodings.Add(Encoding.Unicode);
    SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationYaml);
    SupportedMediaTypes.Add(MediaTypeHeaderValues.TextYaml);
  }

  public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
  {
    if (context == null)
    {
        throw new ArgumentNullException(nameof(context));
    }

    if (selectedEncoding == null)
    {
        throw new ArgumentNullException(nameof(selectedEncoding));
    }

    var response = context.HttpContext.Response;
    using (var writer = context.WriterFactory(response.Body, selectedEncoding))
    {
        WriteObject(writer, context.Object);

        await writer.FlushAsync();
    }
  }

  private void WriteObject(TextWriter writer, object value)
  {
    if (writer == null)
    {
        throw new ArgumentNullException(nameof(writer));
    }

    _serializer.Serialize(writer, value);
  }
}

Pretty much same goes for the input formatter. In this case, you would Deserialize the Yaml content from the client's request and use them in a generic form.

Yaml Input Formatter

public class YamlInputFormatter : TextInputFormatter
{
  private readonly Deserializer _deserializer;

  public YamlInputFormatter(Deserializer deserializer)
  {
    _deserializer = deserializer;

    SupportedEncodings.Add(Encoding.UTF8);
    SupportedEncodings.Add(Encoding.Unicode);
    SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationYaml);
    SupportedMediaTypes.Add(MediaTypeHeaderValues.TextYaml);
  }

  public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
  {
    if (context == null)
    {
        throw new ArgumentNullException(nameof(context));
    }

    if (encoding == null)
    {
        throw new ArgumentNullException(nameof(encoding));
    }

    var request = context.HttpContext.Request;

    using (var streamReader = context.ReaderFactory(request.Body, encoding))
    {
        var type = context.ModelType;

        try
        {
            var model = _deserializer.Deserialize(streamReader, type);
            return InputFormatterResult.SuccessAsync(model);
        }
        catch (Exception)
        {
            return InputFormatterResult.FailureAsync();
        }
    }
  }
}

MediaTypeHeaderValues a simple class where I've setup all the media type headers for my application.

internal class MediaTypeHeaderValues
{
  public static readonly MediaTypeHeaderValue ApplicationYaml
      = MediaTypeHeaderValue.Parse("application/x-yaml").CopyAsReadOnly();

  public static readonly MediaTypeHeaderValue TextYaml
      = MediaTypeHeaderValue.Parse("text/yaml").CopyAsReadOnly();
}

Notice that the YamlInputFormatter’s constructor is accepting a Deserializer where YamlOutputFormatter’s constructor is accepting a Serializer. We build the Serializer and Deserializer with some options tweaking while configuring the formatters in the Startup.cs’s ConfigureServices method.

public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
  services.AddMvc(options=>
  {
    options.InputFormatters.Add(new YamlInputFormatter(new DeserializerBuilder().WithNamingConvention(namingConvention: new CamelCaseNamingConvention()).Build()));
    options.OutputFormatters.Add(new YamlOutputFormatter(new SerializerBuilder().WithNamingConvention(namingConvention: new CamelCaseNamingConvention()).Build()));
    options.FormatterMappings.SetMediaTypeMappingForFormat("yaml", MediaTypeHeaderValues.ApplicationYaml);
  });
}

A simple GET request with Accept header set to application/x-yaml

alt text

A simple POST request with Content-Type header set to application/x-yaml

alt text

Formatter mapper lets you call a Action with a specific format directly through the Url. Setting up a [HttpGet("/api/[controller].{format}")] attribute will return the action result in the format defined in the browser’s url.

[FormatFilter]
[HttpGet]
[HttpGet("/api/[controller].{format}")]
public IEnumerable<Geek> Get()
{
    return new List<Geek>()
    {
        new Geek() { Id = 1, Name = "Fiyaz", Expertise="Javascript", Rating = 3.0M },
        new Geek() { Id = 2, Name = "Rick", Expertise = ".Net", Rating = 5.0M }
    };
}

alt text

Dependencies

I’m using the YamlDotNet library from Antoine Aubry for Yaml’s serializing and desirializing process.

coreformatters's People

Contributors

fiyazbinhasan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.