Is it possible to replace the default JSON serialization of WCF (I'm currently testing with the webHttp behaviour), and passing application/json as the MIME type. In particular, I don't like that by default every property is a key/value pair like:
{"Key":"PropertyName", "Value":"PropertyValue"}
I'm using the service only for JSON-enabled endpoints (requesting data with jQuery + WCF).
You can use a message formatter to change the serializer used to deal with JSON. The post at https://learn.microsoft.com/en-us/archive/blogs/carlosfigueira/wcf-extensibility-message-formatters shows an example on how to change the default serializer (DataContractJsonSerializer) to another one (JSON.NET).
Consider creating classes corresponding to your JSON object structure. In that case you don't have to use Dictionary<> like:
[DataContract]
public class Customer
{
[DataMember(Name="name")]
public string Name{get;set;}
[DataMember(Name="id")]
public int ID{get;set;}
}
This get serialized as:
{"name": "name-value", "id": "id-value"}
Of course, this is just an alternative to what you already have and may not be applicable.
Related
I have a question about a standard pattern or mechanism in spring-hateoas or Spring Rest Data about encrypting the IDs of the Resources/Entities.
The reason I am asking, a requirement to our project is that we don't deliver the id's of our objects to the outside world and they should not be used in GET Requests as Parameters.
I know, Spring Rest Data and spring-hateoas does not give the ids of the objects unless they are configured so but even that case I can see the ids in links.
I know I can use PropertyEditors or Converters to encrypt/decrypt ids before and after Json serialisation/deseritalisation but I just like to know is there a more standard way?
Thx for answers...
If you have the unique 'business id' property of your resource you can configure SDR to use it instead of the entity ID.
First you have to create lookup method of your entity with this unique property:
public interface MyEntityRepo extends JpaRepository<MyEntity, Long> {
#RestResource(exported = false)
Optional<CatalogResource> findByMyUniqueProperty(String myUniqueProperty);
}
Then use it to configure SDR:
#Component
public class DataRestConfig extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.withCustomEntityLookup()
.forRepository(MyEntityRepo.class, MyEntity::getMyUniqueProperty, MyEntityRepo::findByMyUniqueProperty);
super.configureRepositoryRestConfiguration(config);
}
}
After this customization you will have resource URI like this:
http://localhost:8080/myEntities/myUniquePropertyValue1
I have a predefined xml sample which defines the requests and responses, the only part I can't get working with ServiceStack.Text.XmlSerializer is the following snippet, which is basically a list of strings.
<user>
....
<EmailPreferences>
<EmailProgram>Newsletter</EmailProgram>
<EmailProgram>Coupons</EmailProgram>
</EmailPreferences>
I tried using the example Using Structs to customise JSON, but as the title implies that didn't affect the xml serialisation.
ServiceStack uses .NET's XML DataContractSerializer under the hood. So you can decorate the models with any customizations it support. So to get something like the above you could do:
[CollectionDataContract(Name="EmailPreferences", ItemName="EmailProgram")]
public class EmailPreferences : List<string>
{
public EmailPreferences() { }
public EmailPreferences(IEnumerable<string> collection) : base(collection){}
}
Global XML Namespaces
Although you can individually add namespaces to each DataContract a better idea instead is to have all your DTOs share the same namespace, this will prevent the auto-generated and repeating namespaces from appearing in your XML.
As the ResponseStatus DTO is already under http://schemas.servicestack.net/types namespace so if you don't care what your namespace is I would leave it at that.
The easiest way to have all your DataContract's under the same namespace is to put these assembly wide attributes in your AssemblyInfo.cs for each C# namespace your DTOs are in:
[assembly: ContractNamespace("http://schemas.servicestack.net/types",
ClrNamespace = "ServiceStack.Examples.ServiceModel.Operations")]
[assembly: ContractNamespace("http://schemas.servicestack.net/types",
ClrNamespace = "ServiceStack.Examples.ServiceModel.Types")]
I'm new to WCF data services. I have a quite simple data model. Some of its properties have the same type, like this:
public IQueryable<IntegerSum> HouseholdGoodsSums
{
get
{
return GetData<IntegerSum>(DefaultProgramID, "rHouseholdGoodsPrice", IntegerSumConverter);
}
}
public IQueryable<IntegerSum> StructureSums
{
get
{
return GetData<IntegerSum>(DefaultProgramID, "rStructurePrice", IntegerSumConverter);
}
}
The IntegerSum is a very very simple class:
[DataServiceKey("Amount")]
public class IntegerSum
{
public int Amount { get; set; }
}
When I navigate to my service in a web browser, I see the following error message:
The server encountered an error processing the request. The exception message is 'Property 'HouseholdGoodsSums' and 'StructureSums' are IQueryable of types 'IntegrationServices.PropertyIntegrationServices.IntegerSum' and 'IntegrationServices.PropertyIntegrationServices.IntegerSum' and type 'IntegrationServices.PropertyIntegrationServices.IntegerSum' is an ancestor for type 'IntegrationServices.PropertyIntegrationServices.IntegerSum'. Please make sure that there is only one IQueryable property for each type hierarchy.'.
When I get rid of one of these two properties, the service starts working.
I searched for this error message in google, but haven't found a solution.
Is it really not allowed to have two properties with the same type in a data model? If so, why?
Comrade,
To address the error first, you're running into a limitation in the Reflection provider. Specifically, the Reflection provider doesn't support MEST.
That said, there are better approaches to achieve what you're trying to achieve. You should probably not make IntegerSum an entity type (an entity type is a uniquely identifiable entity, which doesn't really fit your scenario). While you can't expose that directly, you can expose it as a service operation. That seems much closer to what you're trying to achieve.
A couple of ways to distinguish between whether or not something should be an entity:
If it has a key already, such as a PK in a database, it should probably be an entity type
If you need to create/update/delete the object independently, it must be an entity type
HTH,
Mark
I'm trying out the API controller in MVC 4 and have a question about best practice when using put, updating an object.
I'm using RavenDB as data storage and I have created a custom MediaTypeFormatter that has a converter of type JsonDynamicConverter that can serialize and deserialize json to a dynamic object. With that said my API controllers Put method looks like this
public void Put(string id, dynamic model) {}
this dynamic object looks sorta like this:
pageModel = {
"id": "pages-2",
"metadata": {
"changed": "2012-02-28T17:16:27.323Z"
},
"parent": {
"id": "pages-1",
"slug": null
},
"children": []
}
so, so far so good but now I need to update my entity with id pages-2.
The UpdateModel does not exist in the ApiController so my question is what is the best/preferred way of doing this?
Simply call RavenDB to load the object with the appropriate ID, make the changes to its contents and persist it again.
No need to worry about any UpdateModel calls. It doesn't apply here.
Be aware of one potential issue since you are including the id in the model. If I sent a PUT command to http://server/controller/pages-3 with that body what would happen? You should probably send me a bad request response or something similar depending on how you want your API to work.
Is there any reason not to be explicit in your parameters? I would define an UpdateModel and take that as parameter instead of the dynamic. Then it also would be able to model validation.
ASP.NET WebApi includes handling of converting from both JSON and XML as input to your controller methods. I'm guessing your combination of custom mediatypeformatter and use of dynamic would be unneccesary in this case, if there is not something I'm missing.
I'm writing a REST WCF service with methods to retrieve a collection of resources and a single resource. My resources are classes based on a single abstract class. In my method to retrieve a collection I have:
[WebGet(UriTemplate = "")]
[ServiceKnownType(typeof(File)), ServiceKnownType(typeof(Text))]
List<ResourceBase> GetCollection();
and that produces XML that looks like this:
<ArrayOfResourceBase xmlns="..." xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ResourceBase i:type="Text">
...
</ResourceBase>
<ResourceBase i:type="File">
...
</ResourceBase>
</ArrayOfResourceBase>
My single object method looks like this:
[WebGet(UriTemplate = "{id}")]
[ServiceKnownType(typeof(File)), ServiceKnownType(typeof(Text))]
ResourceBase Get(string id);
and produces XML like this:
<Text xmlns="..." xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
...
</Text>
Is there a way to get those two xml parts to look the same, that is either to get rid of "i:type" tags in ArrayOf... and convert them to tag name, or force them in the single object response?
There may be several solutions here, but I can think of a few right away:
Change the custom DataContract name of the DataContract class ResourceBase to always be Text. Like so:
[DataContract(Name="Text")]
class ResourceBase
{
...
}
Plug in a DataContractSurrogate to special-case this type
Plug in a custom DataContractSerializerOperationBehavior that plugs in a custom DataContractSerializer child that special cases this type
Use XmlSerializer. See this blog post.