I'm utilizing the Web API in MVC4 to provide a simple API for my web service. I have read the various posts on SO about using [XmlType], [XmlRoot], [XmlElement] etc. on the model to set custom names on the root-element and on the element wrapping each entity, but none of them seem to have an effect at all. The API works fine overall, but the XML-attributes seem to have no effect, leaving me with irrelevant element names.
I've simplified my code somewhat, to make the example more clear, but this is basically what it looks like:
API controller:
public class SomeController : ApiController
{
[HttpGet]
public List<MyViewModel> All()
{
return ApiProvider.All()
.Select(v => new MyViewModel
{
SomeId = v.SomeId
SomeValue = v.SomeValue
}).ToList();
}
}
MyViewModel:
public class MyViewModel
{
public int SomeId { get; set; }
public int SomeValue { get; set; }
}
Current XML-response:
<ArrayOfMyViewModel xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/...">
<MyViewModel>
<SomeId>3</SomeId>
<SomeValue>My value</SomeValue>
</MyViewModel>
</ArrayOfMyViewModel>
Desired XML-response:
<CustomRootName xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/...">
<CustomEntityName>
<SomeId>3</SomeId>
<SomeValue>My value</SomeValue>
</CustomEntityName>
</CustomRootName>
I have made no configuration changes to what serializer I'd like to use, or anything like that.
Am I missing something here, or why can I not change the name of the elements? Is there some other approach to take, or some necessary setting that I'm missing?
Can't you just have a class
CustomRootName : List<MyViewModel>
and return an instance of CustomRootName?
[my reply to your comment follows below]
Yes, that was my view when we started our api but ArrayOfMyViewModel is essentially a pseudo wrapper created by the serialiser and creating a one line wrapper per resource list was that much of a bind. Consider when your api gets more complex and you need to support more complex list types, ie:
<CustomRootName >
<RootType>typeB</RootType>
<CustomEntityName>
<SomeId>3</SomeId>
<SomeValue>My value</SomeValue>
</CustomEntityName>
<CustomEntityName>
...etc
</CustomEntityName>
</CustomRootName>
You would benefit from a consistent interface. Another benefit we found was with documentation. We document our code using xml-doc tags and then auto-generate the api user guide using xslt and a bit of reflection. If you don’t have a wrapper class then there is knowhere to hang the xml-doc tag. So initially it looks like a pain but I was soon convinced.
Related
I have to build a .NET Core REST API and I have about two dozen endpoints that take in simple JSON objects like:-
{
"foo": 23,
"bar": "bar_value"
}
and
{
"foo": 12,
"baz": true
}
etc.
Some properties, such as foo above, are common among several endpoints but have different validation requirements. In some endpoints they are required, in others, they are not and so on. I can't change these JSON payloads as they're generated by a third party I don't have any control over.
How can I map these parameters to endpoints in a .NET Core API method directly, without a class?
I can, of course, create a class for each endpoint, such as
public class SomeObject
{
[Required]
[Range(0, 100)]
public int? Foo { get; set; }
public string bar { get; set; }
}
public class SomeOtherObject
{
public int? Foo { get; set; }
[Required]
public bool Baz { get; set; }
}
...
Note the different validation rules.
But I don't feel like creating some two dozen classes. I'd much rather just specify them directly in the endpoint method:
[HttpPut]
[Route("/some-route")]
public IActionResult SomeAction([Required, Range(0, 100)] int? foo, byte? bar)
{
...
}
[HttpPut]
[Route("/some-other-route")]
public IActionResult SomeOtherAction(int? foo, [Required] baz)
{
...
}
It would be much easier to read and figure out which property is required and when by just looking at the methods instead of opening one of two dozen similarly named class files or opening one single file with two dozen similarly named classes with properties of the same name.
So how can I get .NET Core to parse the JSON and assign the property values to the action method parameters?
I'm not aware of a direct answer to this question as specified, so I'll answer this with an alternative approach as an XY problem based on your statement "It would be much easier to read and figure out which property is required and when by just looking at the methods".
This assumes there's not an easy way document your own API surface area if you're using classes. In your example, you're already writing a large amount of logic in the method signature itself, not to mention potential behaviors for default values, etc., that can make those signatures progressively harder to read and understand, and that's exactly what input model classes and model validation are designed to help encapsulate. Furthermore, now that you've decomposed the model into its parts, it becomes increasingly complex to handle validation issues as a cohesive model, regardless of whether it could be done. By accepting the entire object at once, you can run a ModelState.IsValid check, aggregate errors, or add your own and quickly return that from the controller.
By adding XML documentation to your endpoint methods and input model classes, you also open up the easy path of adding a Swagger page with Swashbuckle, which will provide a simple way for you to inspect what the model value types are and which ones are required, etc., as well as example JSON bodies in the Swagger page itself with full documentation as to the purpose of all the parameters.
While you do end up with a bunch of model classes, it's just a button press away from Visual Studio to hop to your class and see your validation requirements and input types while "in code". If class generation is frustrating, you can quickly drop your JSON samples into a class generator online and get a "pretty good" starting point for the input models: https://json2csharp.com/
I can use [FromBody] for single type , but is there any way to use multiple?
From the searching and reading I've done there is not a way, but i don't know if a way has been added in MVC 6.
If not, where would be best to start with custom way.
What should i be researching and looking for best method or place to hook in just before model binding so i can include my own method?
The best way is to create a composite wrapper:
public class Wrapper
{
public ModelA A { get; set; }
public ModelB B { get; set; }
}
Put Wrapper in the parameter list and mark that [FromBody]. You can't use that attribute more than once because all of the contents of the body are assumed to match the parameter type.
The composite wrapper approach is great if you can easily share your model between the caller and server, but a more generic approach is to use JObject:
using Newtonsoft.Json.Linq; // this gets you to JObject
[Route("svc/[controller]/[action]")]
public class AccountController : Controller
{
[HttpPost("{accountid}")]
public IActionResult UpdateAccount(int accountid, [FromBody]JObject payload)
{
var loginToken = payload["logintoken"].ToObject<LoginToken>();
var newAccount = payload["account"].ToObject<Account>();
// perform update
return this.Ok("success");
}
}
You could probably also go with a Tuple which would give you the concrete types specified in the parameter list. This would be great if your clients were always .NET apps (.NET 4.0 or later, specifically) but you'd probably want to write a helper library to get the right wire format if you were trying to come from AJAX or something similar.
Iam trying to integrate the ServiceStack C# client to connect to the backend ( REST ).
FTR, iam in a PCL Library, using MvvMCross as a the framework on top of Xamarin ( if of any intereset )
The basic communication is working, but now i have to map the response models ( DTOs? ) to the DomainModels i use in the Application.
Iam now getting pretty confused what ServiceStack offers, when DTO and DomainModel is different. There is the talking of AutoMapper, or using ConvertTo or how it relates when you DynamicModel.
In case, i have the feeling like a just have a misunderstandingwhat exactly DTO should be, so dont mind me if i mix up anything, ill try to adapt :)
Lets say my DomainModel would look like
public class Checkout {
public int id;
public String title;
public String foo;
}
The response DTO looks like this ( in json )
public class CheckoutDto {
public int id;
public String name;
public String bar;
}
Now i would like to map name to title and bar to foo when using the ServiceStack client. Iam now not sure how to incorporate the idea of the "response" in the ServiceClient 4.x API comparing to the DTO itself ( should it be the same? )
_restClient.Get<CheckoutResponse>("/checkout/1");
My concrete questions are:
- what bet approach should i take with ServiceStack?
- should i use AutoMapper with Mapper.Create / Mapper.Map to convert from DTO / toDTO?
- do i mix up terminology ( so my question is hard to understand or even to complex? )
I have read the several posts on service-stack regarding this topic, including the docs on servicestack / wiki and also googles resources - i seem to just dont get the point.
Thanks!
I recommend walking through some the existing examples.
Email Contacts is a good example to start with as it takes you through creating a ServiceStack solution from scratch with the recommended structure namely putting all your Data Transfer Objects (DTOs) in a separate assembly, e.g. Project.ServiceModel
Many ORM's like OrmLite lets you persist POCO's in your preferred RDBMS, so in a lot of cases you can just persist your populated DTO directly in the database as-is. But when the schema for your DTOs and Data Models diverge then it's a good idea to map them, which the built-in Auto-Mapping easily lets you do.
When calling services you typically will not need to specify any urls when using ServiceStack's typed C# Service Clients as it will automatically use the preferred route when you pass in the populated Request DTO, e.g:
[Route("/checkout/{Id}")]
public class Checkout : IReturn<CheckoutResponse>
{
public int Id { get; set; }
public String Title { get; set; }
public String Foo { get; set; }
}
You can then use the above Request DTO in your client like:
var client = new JsonServiceClient(BaseUrl);
CheckoutResponse response = client.Get(new Checkout { Id = 1 });
I have a Generic Envelope class that i use as the common return object for the WebAPI as follows:
public class ApiEnvelope<T>
{
public bool Success { get; set; }
public Error Error { get; set; }
public Data<T> Data { get; set; }
}
Then I construct a HttpResponseMessage using:
Request.CreateResponse<ApiEnvelope<whatever>>(HttpStatusCude.OK, model);
The problem i have is that i would like the xml to be somewhat standard however the root name of the xml being returned is not standard and is coming through as ApiEnvelopeOfwhatever.
My question is how can i get the root name to be ApiEnvelope regardless of the type?
With generic class you got no chance, remove generic specification and set Data propert type to object.
I had a similar question and I got a decent answer, (I know this is old but it was a good answer): How to resolve Swashbuckle/Swagger -UI model naming issue for generics?
Now this is only part of the solution for your question, so you should look at Github repo: MakeGenericAgain. Use that to "regeneric" the resultant generated code, (big heads up: if you use this on the entire code and not just names of types, you will have a mess if you have properties name things like "NumberOfUnits" because that becomes "Number").
Sidenote:
If you want to "level up" your skills here, then use Rolsyn's SyntaxWalker to apply the renaming, and at the same time "cleanup" duplicated classes, as many design their REST-APIs with few shared "models" so a User and a Company might hace identical "Address" -properties based on identically shaped classes but it they are defined twice your NSwag -generated code will have Address and Address2, however using Roslyn, you can identify these ande rewrite the code to give a "perfect result".
I have created a .net Web Api project. I already have an existing Logic and Data layer and want to expose some of the data using Web Api. Everything works fine when the content-type returned is XML - all relevant records and all fields are returned correctly. However if I change the content-type to JSON - all relevant records are returned BUT only with the ID.
I have verified this using Fiddler and different browsers.
I could create a dumby class and hydrate it but that is a pain and a lot of work. Any ideas of what is going on?
PS The classes being returned have fields that only include simple types (99% sure).
#Will that was it!
I have to go back and add "[DataContract]" to my classes and "[DataMember]" to the members and the data then comes through.
http://msdn.microsoft.com/en-us/library/ms733127.aspx
namespace MyTypes
{
[DataContract]
public class PurchaseOrder
{
private int poId_value;
// Apply the DataMemberAttribute to the property.
[DataMember]
public int PurchaseOrderId
{
get { return poId_value; }
set { poId_value = value; }
}
}
}