0

I have asp.net core 2.2 web Application. The application contains Command and Query Actions, Command Actions must return typed json response:

{
   $type:"A.B.Customer, x.dll ",
   id: 11231,
   name: "Erwin .."
}

Query Actions must return non typed response:

{
  id: 34234,
  name: "Erwin .. "
}

We can choose one outputformatter for Json responses at startup.

 services.AddMvc().AddJsonOptions(o =>
                {
    SerializerSettings.TypeNameHandling=Newtonsoft.Json.TypeNameHandling.Objects
   // SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None
}

So How can I change output formatter for same response type (application/json) by action?

1 Answer 1

2

There are multiple ways to do that.

One would be to directly call JSON.NET Methods and pass your settings to it.

JsonSerializerSettings settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Objects
};

return base.Content(JsonConvert.SerializeObject(query, settings), "application/json");

Alternatively, return a JsonResult

JsonSerializerSettings settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Objects
};

return new JsonResult(query, settings);

Be careful with the second example. In .NET Core 3.0, JSON.NET isn't hard-wired into ASP.NET Core anymore and ASP.NET Core ships w/o JSON.NET and uses the new System.Text.Json classes base don span.

In ASP.NET Core 2.x, JsonResult accepts JsonSerializerSettings as second parameter. From ASP.NET Core 3.x, JsonResult accepts object and depending on the serializer used, a different type is expected.

This means, if you use the second example in your code, it will (at first) break, when migrating to ASP.NET Core 3.0, since it has no dependencies on JSON.NET anymore. You can easily add JSON.NET Back to it by adding the Newtonsoft.Json package to your project and add

servics.AddNewtonsoftJson();

in your ConfigureServices methods, to use JSON.NET again. However, if in future, you ever decide to move away from JSON.NET and use System.Text.Json or any other Json serializer, you have to change all places where that's used.

Feel free to change that to an extension method, create your own action result class inheriting from JsonResult etc.

public class TypelessJsonResult : JsonResult
{
    public TypelessJsonResult(object value) : base(value)
    {
        SerializerSettings.TypeNameHandling = TypeNameHandling.None;
    }
}

and reduce your controller's action code to

return new TypelessJsonResult(query);
Sign up to request clarification or add additional context in comments.

5 Comments

There are too many actions to change, so I will try to prepare ActionFilter/ResultFilter for this requirement,Thanks for detailed response @Tseng
@ozz: I'm curious: When you are using (typed) commands, why are you having multiple endpoints? (that's the only reason why "too many actions to change" can be said). When you are using commands its basically RPC and the command type alone is enough to distinguish the commands by their full quallified name. The need for a full qualified type is that you have a base class and an action which accepts the base type. you'd only have multiple actions if each action accepts the most specific type name, but then, you don't need the $type parameter as JSON deserializer hint. No?
I think I misrepresented the problem, I'm not using $type information as command dispatcher. I created generic Create,Edit,Display pages for my Entities, (front-end:Vue+Vuetify). I want to know type information for this Create and Edit pages on the server side. So I'm using typed serialization-deserialization for them. On the other side, I have also created Generic/Dynamic Display for ViewModel objects. There is no "type information" requirement for them for now :)
If I try to make an abstraction, 1- Command (Create/Update - I Need typed deserialization), 2- Query, 2a - Query For Command (New/Edit pages-I need typed serialization) 2b - Just Query (View Pages - No need typed serilazation for now) Thanks for help, the problem is solved for now :)
If you want to set a statuscode for the JsonResult do this: new JsonResult(object) { StatusCode = (int)HttpStatusCode.Created }. Normally JsonResult returns 200: Ok, so if you want to return a created resource (or anything else), you need to manually set the statuscode.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.