How would I go about about using LINQ to JSON in the .net 4 Client Profile in C#. I'd like to query certain json responses as shown in msdn blog post without having to write out a contract (datacontract, servicecontract, etc). I really only need to query(read) the response, I don't need to modify the json response. (Also would a datacontract be faster than LINQ to JSON?)
Alternatively I could use XML or the full .net 4 framework, but I'm hoping that this can be avoided. I can use external libraries if it's better than installing the whole framework.
JSON.net is quite popular and seems to be what you're after.
If your service is used by Ajax (jQuery) clients, you will get the best performance by using JSON.
Another recommendation; in order to get rid of the same domain policy, I recommend you to enable crossDomainScriptAccessEnabled functionality:
<webHttpBinding>
<binding name="myHttpBinding" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
Regarding the DataContract; in your scenario, a DataContract is not really needed.
Example code:
Your Service:
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class BlogService {
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public List<Article> GetBlogArticles()
{
return Article.GetDummyArticles.ToList();
}
}
Article Class (excerpt):
public class Article {
public string Title { get; set; }
public string Body { get; set; }
public static IEnumerable<Article> GetDummyArticles() {
yield return new Article { Title = "Article 1", Body = "sdlkfjsdlkfjskl" };
yield return new Article { Title = "Article 2", Body = "sfsfsdfd23434wfdfsfdfkfjskl" };
}
}
For your scenario I actually can't find a reason to use any (3rd-party) library since WCF4 already contains native support for JSON with or without Padding.
Related
I'm migrating a .NET Framework SOAP Web Service (Server Side) to a new .NET 6 project.
I used DataContract and DataMember with no issues until I reached a WS which had to return XML attributes.
Then I read the official documentation but was not able to find a way to return attributes inside my XML elements.
They suggest to use XmlSerializer and the "XmlAttribute" attributes, but they seems to be ignored by .NET 6.
Am I forced to roll it back to .NET Framework or is there anything I can do?
Here is a simple example that's not working:
Of course if I switch it back to DataModel it works, but I am not able to have XML attributes.
What I want to achieve is
<BankingTransaction operation="opName">
<amount>100</amount>
</BankingTransaction>
THE INTERFACE
[ServiceContract]
[XmlSerializerFormat]
public interface IBankingService
{
[OperationContract]
public BankingTransaction ProcessTransaction();
}
THE SERVICE IMPLEMENTATION
public class BankingService: IBankingService
{
public BankingTransaction ProcessTransaction()
{
BankingTransaction bt = new BankingTransaction();
bt.amount = 1000;
bt.Operation = "Test";
return bt;
}
}
THE MODEL
public class BankingTransaction
{
[XmlAttribute]
public string Operation;
[XmlElement]
public int amount;
}
Thanks
A PIECE OF THE program.cs file
builder.Services.TryAddSingleton<IBankingService, BankingService>();
app.UseSoapEndpoint<IBankingService>("/Service.asmx", new SoapEncoderOptions());
How can I export a C# class (DTO) in the dtos.ts file generated with npm run typescript-ref http://localhost:5000 src/myproject without referencing in the request class?
Note: we have several C# DTO classes (MutationAddressChange, MutationCEOChange...) that we map to the domain class using automapper. So we want to use the C# DTO classes as well in Angular to populate the corresponding type (e.g.MutationAddressChangesCreateDTO) and send it to the web server. Therefore, in the CreateMutationRequest class, we accept an object instead of a specific class.
example DTO-Class:
public class MutationAddressChangesCreateDTO
{
public string Street { get; set; }
public string POBox { get; set; }
public string Zipcode { get; set; }
}
ServiceStack Request-Class
public class CreateMutationRequest : IPost
{
public object Mutation { get; set; }
}
Angular expected use:
{
var mutationAddressChangesCreateDTO= new MutationAddressChangesCreateDTO();
mutationAddressChangesCreateDTO.dateOfMutation = ...
const request = new CreateMutationRequest ({
mutation: mutationAddressChangesCreateDTO,
});
this.client.post(request)
...
}
A limitation of Add ServiceStack Reference feature is that your DTOs cannot have any object or interface properties which creates a black hole in your Services contract that's impossible to generate a Typed API for.
I'd recommend against having any object or interface properties in your DTOs which other than being a source of runtime issues is also limited by security restrictions.
You could use an untyped data structure like a Dictionary<string,string> to store arbitrary values, you can some find other alternatives in this Customer Forums thread.
Although it's discouraged you could still have object properties in your ServiceStack Request DTOs, you just wont be able to generate a typed API for them but you should still be able to send them as an anonymous arg, e.g:
this.client.post(request, { mutation: dto });
Object properties are handled with JS Utils by default which should deserialize it into a Dictionary<string,object> which you should be able to convert back into a C# type using ServiceStack's Reflection Utils, e.g:
public object Any(CreateMutationRequest request)
{
var payload = request.Mutation as Dictionary<string,object>;
var payloadRequest = payload.FromObjectDictionary(typeof(TheType));
}
A similar approach to this that avoids using object is to send a serialized JSON payload in a string property, e.g:
request.mutation = JSON.stringify(payload);
Which you can deserialize using JS Utils again, e.g:
public object Any(CreateMutationRequest request)
{
var payload = JSON.parse(request.Mutation);
var payloadRequest = payload.FromObjectDictionary(typeof(TheType));
}
With that said I don't recommend any of these untyped strategies and would personally create Typed services for each API that's needed which is more intuitive, discoverable & resilient, any shared functionality can easily be handled in your Services implementation using ServiceStack's AutoMapping and .NET's powerful reflection capabilities.
I'm seeing C# URI types serialized to JSON in an ODATA 3 controller in my WebAPI 2 project as an array of segments that does not include the domain. I've tried everything I can think of to change this (including fiddling with the serialization settings and even trying out the contract serializer instead of JSON.Net). Nothing seems to change the behavior. Note, I am not using .Net Core. Here is a code sample, condensed into a single snippet.
namespace WebApplication1.Controllers
{
public class MyObject
{
public Uri Url { get; set; }
public string Name { get; set; }
public string ID { get; set; }
}
public class MyObjectsController : ODataController
{
private static ODataValidationSettings _validationSettings = new ODataValidationSettings();
public IHttpActionResult GetMyObjects(ODataQueryOptions<MyObject> queryOptions)
{
try
{
queryOptions.Validate(_validationSettings);
return Ok<IEnumerable<MyObject>>(new List<MyObject>() { new MyObject() { ID="asdf", Name="123rwe", Url = new Uri("http://www.webapp.com/sites/page.html") } });
}
catch (ODataException ex)
{
return BadRequest(ex.Message);
}
}
}
}
This generates the following JSON in the browser:
{
"odata.metadata":"http://localhost:51607/odata/$metadata#MyObjects","value":[
{
"Url":{
"Segments":[
"/","sites/","page.html"
]
},"Name":"123rwe","ID":"asdf"
}
]
}
This is what I'd like (without changing the Url property to a string):
{
"odata.metadata":"http://localhost:51607/odata/$metadata#MyObjects","value":[
{
"Url":"http://www.webapp.com/sites/page.html","Name":"123rwe","ID":"asdf"
}
]
}
Any thoughts?
UPDATE:
Further research is suggesting that serialization behavior for URI types in WebAPI ODATA is controlled by the odataentityreferencelink and odataentityreferencelinkserializer classes. Specifically, URI type appear to be converted to odataentityreferencelink types which are then serialized in the manner I posted above (as an array of segments not including the root domain). I still need to know how to change this behavior, however the documentation for these two classes is not proving helpful. Last, I've confirmed this problem is not specific to the JSON output format. The serialization behavior for both XML/Atom and JSON are identical: URIs are broken down into an array of segments.
MS Premier support provided a final answer to this which I'll share below.
There is no option to directly JSON serialize an URI type, normally it would be broken into array of segments as you are observing in your code
The domain name will be eliminated as a normal scenario
The option you can go for is to create a custom URI Converter deriving from JSONConverter which is a part of Newtonsoft.Json namespace
Version 1 of my ASP.NET Web API for Ember.js was producing JSON that looked like this:
[{"id":1,"name":"House of Crap","category":"Retail","street_name":"Washington Street"},
{"id":2,"name":"Sketchy Automotive","category":"Automotive","street_name":"4th Street"},
{"id":3,"name":"Toxins Are Us","category":"Chemical","street_name":"Highway 93"},
{"id":4,"name":"Tricky Restaurant","category":"Restaurant","street_name":"4th Street"}]
I need something that looks like this:
{"property":
[{"id":1,"name":"House of Crap","category":"Retail","street_name":"Washington Street"},
{"id":2,"name":"Sketchy Automotive","category":"Automotive","street_name":"4th Street"},
{"id":3,"name":"Toxins Are Us","category":"Chemical","street_name":"Highway 93"},
{"id":4,"name":"Tricky Restaurant","category":"Restaurant","street_name":"4th Street"}]}
One of my subs accomplished this as follows: He created a simple view-model class.
namespace EnvironWeb.ViewModels
{
public class PropertyVM
{
public IEnumerable<property> property { get; set; }
}
}
He then made the GetProperties controller method of the type of the new class.
public PropertyVM GetProperties()
{
var model = new PropertyVM();
model.property = repository.GetAll();
return model;
}
It's clever, but is it the best approach? The JsonConverter looks promising, but I'm not sure I can accomplish it with the JsonConverter.
This is not the best approach, this is the correct approach :)
Bur I would suggest to review your model. Why do you need root property in the answer? Does it have any business meaning? If only reason for this root property is some simplification of code on client side - may be it's better to keep API clean and just do the work on client side?
I have a question on the implementation of android -> JSON -> RESTful WCF webserive architecture. I'm primarily coming from a C# pattern based background so finding the android architecture hard to get my head around. The way I have designed my C# webservice is to have a whole "model" namespace that defines all my business objects such as User, UserProfile, UserSearchCriteria, UserPhoto etc as CLR objects.
I have exposed my webservice interface through WCF using the RESTful model, combined with request/response pattern which I am used to. One example of a REST web method is as follows.
[OperationContract]
[WebInvoke(
Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/GetSeeds"
)]
GetSeedsResponse GetSeeds(GetSeedsRequest request);
Response object
[DataContract]
public class GetSeedsResponse
{
public GetSeedsResponse(List<Seed> seeds)
{
Seeds = seeds;
}
[DataMember]
public List<Seed> Seeds { get; set; }
}
Request object
[DataContract]
public class GetSeedsRequest : BaseRequest
{
public GetSeedsRequest(int userId, int numberToTake, int startPosition)
{
NumberToTake = numberToTake;
StartPosition = startPosition;
UserId = userId;
}
[DataMember]
public int NumberToTake { get; set; }
[DataMember]
public int StartPosition { get; set; }
[DataMember]
public int UserId { get; set; }
}
Note: all my request objects inherit from my own custom base request object which merely provides them all a common header for authentication, as follows (I am not sure if this is the best way to handle authentication but it is what I am familiar with so have done it this way for now)
[DataContract]
public abstract class BaseRequest
{
[DataMember]
public Header Header { get; set; }
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.2022")]
[System.SerializableAttribute]
[System.Diagnostics.DebuggerStepThroughAttribute]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:MyStory:Web:Services:ServiceModel:Headers")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="urn:MyStory:Web:Services:ServiceModel:Headers", IsNullable=true)]
public class Header
{
public int UserId { get; set; }
public string SessionToken { get; set; }
}
So far I have managed to successfully call the RESTful webmethod from android with the following code in an AsyncTask background worker.
protected ArrayList<Seed> doInBackground(String... params)
{
try
{
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(SERVICE_URI);
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
JSONObject data = new JSONObject();
data.put("UserId", 1);
data.put("NumberToTake", 10);
data.put("StartPosition", 0);
StringEntity entity = new StringEntity(data.toString());
post.setEntity(entity);
HttpResponse response = client.execute(post);
}
...
}
I would then seek to extract the response and manually construct a "Seed" object based on an android class I would define, matching the properties of the CLR version, and manually extracting from the JSON response the indexed fields for which I would know which one corresponded to which property.
My question is in two parts
1) I cannot figure out how to pass the header object. I have tried the following
JSONObject header = new JSONObject();
header.put("UserId", 1);
header.put("SessionToken", "");
JSONObject data = new JSONObject();
data.put("UserId", 1);
data.put("NumberToTake", 10);
data.put("StartPosition", 0);
data.put("Header", header);
But this fails to work with a generic "Bad request error" exception and the webservice doesn't even enter the webmethod (I have set a break point on line 1 which gets hit without the header, but doesn't get hit when I include the header), so I assume I am not understanding JSON properly or the way to pass an embedded object in the Request object
2) Am I doing the whole architectural approach correct? It seems quite laborious and prone to error to be manually constructing array indexed requests and responses for every web service call. How should I be structuring my project, creating matching android objects for all CLR objects my webservice wants to accept as parameters or return as response objects? Is there a lot more power to JSON that I am not aware of that I should be using? With the requests, do I need to create bespoke individual AsyncTask objects for every single web service call I might make? There are about 40 different web methods my app will call, does this mean 40 AsyncTask objects kept in a package somewhere in my codebase? I'm struggling to figure out the "best practices" for designing a decent sized app with decent amounts of web service interaction, if anyone has any books they could reccomend or tutorials that touch on best practices for android project design, architecture for my scenario then I would be very grateful.
Apologies for the length of the post
Decouple the Android side from the Windows server side. The reason we use JSON and REST is that they are system agnostic. Don't worry about the structure on the Windows side. Instead focus on what JSON request will work for the server, and focus on creating that JSON on Android.
First, get a REST client like POSTMan and figure out what the REST call looks like, and what the JSON body looks like.
Then, figure out how to make Android send that body.
Finally, figure out how to make Android generate the JSON body programatically. For this last one, I strongly recommend Gson. It will let you work with higher level objects instead of constructing your JSON manually. If you update your request with the JSON body I'll update this response with how it could be generated in Gson.
As a side note, I recommend you look at OkHttp instead of the Apache HTTP client. It's much more full featured and robust. This isn't necessary at all, but it will make your life easier.