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 });
Related
I have a Blazor Server .net 6.0 app that I wish to consume a number of API's in.
One SOAP API is setup using the Service Reference wizard and has built the proxy class and models and I can use this without issue.
I have two more that are oData based, I've managed to query both using HttpClient - for which one uses oAuth 2.0 bearer tokens, the other basic authentication.
I am able to query various functions on both oData feeds and get a valid JSON string returned. The issue I'm having is understanding the data models around them.
For one of them I created my own data model class and manually replicated the models (there is not much being offered by this API). I can successfully deserialise the JSON response to my manually typed model (although for single items I deserialise direct to the model (EmployeeModel) for lists I had to add a second class (ODataEmployeeModel) to strip out the JsonProperty("odata.context") string) like so
public class ODataEmployeeModel
{
[JsonProperty("odata.context")]
public string? Metadata { get; set; }
public List<EmployeeModel>? Value { get; set; }
}
public class EmployeeModel
{
public string? DisplayId { get; set; }
public string? Title......
}
The other is a well-developed API offing a lot of data documented in the $metadata including complex models. What is the best way to consume the $metadata?
I was hoping that I could scaffold classes to match the models / entities much like scaffolding from a database using EF but most of my reading (or at least my understanding of my reading) seems to indicate that I should add NuGet package and generate a proxy class and the data classes for the service all in one go.
This I assume this would mean that my own HttpClient code is moot? What (if any) is the preferred / better way to connect? I will be using various filters etc.. on the oData requests and I have these working perfectly with my typed HttpClient setup.........
Is the generated proxy from a plugin like ODataV4ClientGenerator the better way of doing things?
Any help / suggestions / guidance is much apricated.
You can use the dynamic type if you don't know what the object looks like.
Assuming the API returns a JSON object.
class Response
{
public int IKnowThisField { get; set; }
public dynamic ButIDontKnowThis { get; set; }
}
JsonConvert.Deserialize<Response>(data);
I have a json String(array) like this:
[{"user":{"name":"abc","gender":"Male","birthday":"1987-8-8"}},
{"user":{"name":"xyz","gender":"Female","birthday":"1987-7-7"}}]
and want to parse it to json object using .net4.0 framework only, and i cannot use DataContractJsonSerializer as it requires class and i am receiving dynamic data over web services within 1 minute which keep changing and it is in Name-value format,i tried using JavaScriptSerializer but i am unable to add system.web.extension in my vs2010 project .net4.0 supported framework,and i don't want to use any third party library,actually i am New-bie in wpf,so please it would be great help,thanks in advance!
Well there are two main issues I can see here, and one additional.
1) If you do not have particular class that you could deserialize JSON to, then you have to rely on some "dictionary-like" structure (e.g. dynamic or JToken)to be able to access all fields. However data you presented seems to be structured, so maybe consider creating POCO to get advantage of strongly-typed structure. Both can be easily achieved using ready-to-use libraries.
2) You say you don't want to use any third party library, but actually there is nothing wrong with it. Actually you should be doing so to avoid reinventing the wheel as Tewr mentioned. It's perfectly fine to use in fact industry-standard library such as Newtonsoft Json so you can avoid tons of bugs, unnecessary work and future troubles. If your point is to learn by writing JSON (de)serializer it's perfectly fine, but I'd recommend against using it in production code.
Side note: you mentioned you receive data over web-service, and it seems you receive simply JSON array (as top-level object). It's considered as security hole. More information may be found here:
https://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx/
What are "top level JSON arrays" and why are they a security risk?
EDIT 2017-11-05:
Ok, so you should create classes representing response from your web service (you can use feature of VS called Edit > Paste Special > Paste JSON As Classes):
public class Response
{
public User[] users { get; set; }
}
public class User
{
public string Name { get; set; }
public string gender { get; set; }
public string birthday { get; set; }
}
Now using Nuget install package Newtonsoft.Json and using following code you'll deserialize JSON response to .NET classes:
string responseText = "";//Get it from web service
var response = JsonConvert.DeserializeObject<Response>(responseText);
Hope this help!
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.
I have reviewed Microsoft's tutorials on RESTFUL APIs and though I have a general understanding of how to create one, I'm at a lost on what exactly I should do.
Scenario: I have a separate Windows program that contains an API you can use written in C#. The program's job is to take a series of locations and return the mileage for those locations. A DLL is used for this. I want to create a separate program (a RESTFUL web service in C#) that users can enter the values through a URL to obtain the mileage. The user can enter 2 or 20 locations maximum. There are also different types of mileages (modules) that can be used to return different types of mileages (the separate windows program handles this).
A location would have the following properties: ID, City, County, State, Zip Code.
I'm not exactly sure how to implement this. What should be in my class? What should be in my controller exactly? I was thinking I could have a single class that keeps track of all the properties of a location.
My biggest concern is also the controller. I'm not sure how to write it because I don't know how the URI should be. I think that a uri like /mileagetype/loc1/loc2/loc3/locx... might be too lengthy since the user can enter up to 20 locations.
You can create WCF Rest WebService to separate out the functionality from your app. Have a look at this article for creating rest full webservices
You can easily use Web Api 2.0 for this. Which is what it was intended for and is perfect for your use case.
Getting started with Web Api 2.0 from Microsoft
Your web API controller would contain just the end point, via URI's to the outside world and you would then go to your DLL for all of the actual logic.
For example on the client side they can pass you an entire complex JSON object that contains all of the properties you mentioned. On the server side (inside your Web API project) you can have a data transfer object with it's sole purpose is to bind to that JSON data coming from the client.
A simple solution:
On the Server your controller to handle the end-points can look like the below example for a very simple GET request.
public class MileageServiceController : ApiController
{
// GET: api/MileageService?locations=100NewYork&locations=300NewJersey
public string Get([FromUri] String[] locations)
{
String value = String.Empty;
//TO DO - GOT TO DLL and get milage
foreach (String loca in locations)
{
//you could go to your DLL here
//value += DLL.GetMilage(loca.ID, loca.City, etc...
value += loca; //for testing
}
return value;
}
}
I wouldn't worry too much about how long the URL will get that isnt really a problem since
it will more than likely be generated by a client consumer which will be implemented in JavaScript or any other programming language.
A more elegant solution:
For the more elegant solution you can create a DTO (Data Transfer Object) on your server side API.
From there you can then pass complex objects from the client via a POST.
Your DTO can look like this:
public class Location
{
public int ID {get; set;}
public string City {get; set;}
public string County {get; set;}
public string State {get; set;}
public int ZipCode { get; set; }
}
Your Controller can look like this:
// POST: api/MileageService - accept an array of location DTO's
public void Post([FromBody]Location[] locations)
{
//Go to DLL and figure out milage for each DTO
}
More on complex types and web API
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.