Unable to deserialize service response when using servicestack MsgPack client - servicestack

Am getting below error when trying to deserialize the response from the service while using servicestack MsgPackServiceClient.
Exception: {"Cannot deserialize member 'test1' of type 'System.Int32'."}
InnerException : {"Cannot convert 'System.Int32' type value from type 'FixedRaw'(0xA4) in offset 1."}
Server side Servicestack Service:
public class TestService : Service
{
public test Get(test s)
{
return new test { test1 = 12, test2 = "testvalue", Domian = "1234" };
}
}
Server side DTO:
[Route("/test")]
public class test
{
public int test1 { get; set; }
public string test2 { get; set; }
public string Domain { get; set; }
}
Client Side code:
class Program
{
static void Main(string[] args)
{
MsgPackServiceClient c = new MsgPackServiceClient(#"http://localhost:52862/");
var result = c.Get<test>(#"/test");
}
}
Client side dto:
public class test
{
public int test1 { get; set; }
public string test2 { get; set; }
}
Client side we don't need Domain property. When we try to get the values, above exception is thrown.
When we add Domain property it works fine and we are able to get values.
Do we really need to have all the properties?
Please help me in solving this issue. Thanks for your time.

If you're using a Binary Format like MsgPack you should use the exact DTOs that were used for serialization which many Binary Serializers are designed to expect.
If you just want to use a partial DTO on the client you should use a flexible Text Serializer like JSON instead.

Related

ServiceStack - Dynamic/Object in DTO

I am running into an issue while looking at SS.
I am writing a custom Stripe implementation and got stuck on web hooks, this in particular:
https://stripe.com/docs/api#event_object
data->object - this can be anything.
Here is my DTO for it:
public class StripeEvent
{
public string id { get; set; }
public StripeEventData data { get; set; }
public string type { get; set; }
}
[DataContract]
public class StripeEventData
{
[DataMember(Name = "object")]
public object _object { get; set; }
}
My hope is to basically just get that object as a string, and then parse it:
var invoice = (StripeInvoice)JsonSerializer.DeserializeFromString<StripeInvoice>(request.data._object.ToString());
Unfortunately the data that is returned from ToString does not have quotes surrounding each json property's name:
Capture
So, the DeserializeFromString returns an object that has everything nulled out.
Why does SS internally strip the quotes out? Is this the proper way to handle a json member that can be one of many different types? I did try the dynamic stuff, but did not have any luck with that either - basically the same result with missing quotes.
I searched very thoroughly for the use of objects and dynamic within DTOs, but there really was nothing that helped with this question.
Thank you!
The issue is that you should never have an object type in DTOs as the serializer has no idea what concrete type to deserialize back into.
The Stripe documentation says object is a hash which you should be able to use a Dictionary to capture, e.g:
public class StripeEventData
{
public Dictionary<string,string> #object { get; set; }
}
Or as an alternative you could use JsonObject which provides a flexible API to access dynamic data.
This will work for flat object structures, but for complex nested object structures you'll need to create Custom Typed DTOs, e.g:
public class StripeEventInvoice
{
public string id { get; set; }
public StripeEventDataInvoice data { get; set; }
public string type { get; set; }
}
public class StripeEventData
{
public StripeInvoice #object { get; set; }
}

How to set GCM priority with Azure Notification Hub

I am currently using Azure Push Notification Service to send messages to android phones. According to This link you can set the priority of a GCM message to help deal with apps in Doze mode.
Here is how I currently use it:
string content = JsonConvert.SerializeObject(new GCMCarrier(data));
result = await Gethub().SendGcmNativeNotificationAsync(content, toTag);
here is GCMCarrier
public class GCMCarrier
{
public GCMCarrier(Object _data)
{
data = _data;
}
}
Now how do I add priority to the message? The constructor to send a GCM only has a data parameter?
Or can I simply add it to my `GCMCarrier" object along with data?
Give a try to the way someone use - add the Priority field to the payload. It was discussed recently in the Github repository as the issue. Windows Phone has that functionality in the SDK, while it looks like the Android does not. But Notification Hubs, AFAIK, is pass-through mechanism, so the payload will be treated by GCM itself.
You can enhance your current model and add required properties in correct format and then convert it to json payload.
public class GcmNotification
{
[JsonProperty("time_to_live")]
public int TimeToLiveInSeconds { get; set; }
public string Priority { get; set; }
public NotificationMessage Data { get; set; }
}
public class NotificationMessage
{
public NotificationDto Message { get; set; }
}
public class NotificationDto
{
public string Key { get; set; }
public string Value { get; set; }
}
Now you can convert your data with json converter but remember use lowercase setting in JsonConverter otherwise there might be expection on device. I have implementation of this in LowercaseJsonSerializer class.
private void SendNotification(GcmNotification gcmNotification,string tag)
{
var payload = LowercaseJsonSerializer.SerializeObject(gcmNotification);
var notificationOutcome = _hubClient.SendGcmNativeNotificationAsync(payload, tag).Result;
}
public class LowercaseJsonSerializer
{
private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
ContractResolver = new LowercaseContractResolver()
};
public static string SerializeObject(object o)
{
return JsonConvert.SerializeObject(o,Settings);
}
public class LowercaseContractResolver : DefaultContractResolver
{
protected override string ResolvePropertyName(string propertyName)
{
return propertyName.ToLower();
}
}
}

ServiceStack "Handler for request not found" when it is working for dozens of similar DTOs

I have been using ServiceStack for months now. It has been working great for awhile and I've used many advanced approaches and Redis integration. I have a license, so my issue is not regarding a license issue, but I wonder if it is related. It almost looks like I have hit a maximum of DTO or paths, but I do not get any such error, simply the "Handler for request not found". So here is my question: how can you debug and isolate this error? I have read all the posts I can find on proper formats for DTO and DTO filters and I have been doing this long enough that I can see nothing wrong in this regard. Identically styled DTO's and paths work, but new ones fail, or so it seems. Even if I find there is something I am doing wrong in my DTO setup, the question remains, is there a way to debug this? Of course, finding what I'm doing wrong, if that is the case, is the first question.
Here is my code, AppHost first:
.Add<UsersCredentials>("/userscredentials", "GET")
.Add<UserCredential>("/userscredentials", "DELETE")
.Add<UserCredential>("/userscredentials/{UserName}", "POST PUT DELETE")
.Add<UserCredential("/userscredentials/{UserName}/(Permissions}/{System}/{ParamSet}/{Instrument}/{Interval}", "POST PUT DELETE")
DTO:
[Route("/userscredentials", "GET")]
public class UsersCredentials : IReturn<UsersCredentials>
{
public string UserName { get; set; }
public string Permissions { get; set; }
public string System { get; set; }
public uint ParamSet { get; set; }
public string Instrument { get; set; }
public uint Interval { get; set; }
} //Request DTO
[Route("/userscredentials", "DELETE")]
[Route("/userscredentials/{UserName}", "POST PUT DELETE")]
[Route("/userscredentials/{UserName}/(Permissions}/{System}/{ParamSet}/{Instrument}/{Interval}", "POST PUT DELETE")]
public class UserCredential : IReturn<UserCredential>
{
public string UserName { get; set; }
public string Permissions { get; set; }
public string System { get; set; }
public uint ParamSet { get; set; }
public string Instrument { get; set; }
public uint Interval { get; set; }
} //Request DTO
And Service:
// UsersCredentials
public class UsersCredentialsResponse
{
public string Result { get; set; }
public ResponseStatus ResponseStatus { get; set; } //Where Exceptions get auto-serialized
}
public class UsersCredentialsService : Service
{
private bool init = false;
public object Get(UsersCredentials request)
{
return (request);
}
public object Post(UserCredential request)
{
return request;
}
public object Put(UserCredential request)
{
return request;
}
public void Delete(UserCredential request)
{
}
}
I use "POSTMAN" for debug and send this as a POST:
http://sun:1300/userscredentials/a?format=json
It works. Then I send as POST:
http://sun:1300/userscredentials/a/b/c/1/d/2?format=json
and get, "Handler for Request not found: Request.HttpMethod: POST Request.PathInfo: /userscredentials/a/b/c/1/d/2 Request.QueryString: format=json Request.RawUrl: /userscredentials/a/b/c/1/d/2?format=json"
Routing:
You shouldn't be defining the routes in the AppHost using the .Add<T> method as well as using [Route("/route", "METHOD")] on the DTO.
You only need to use one method. So this may cause conflict, and certainly extra maintenance. I recommend using just the latter, of the Route attribute. So remove the Add rules from your AppHost as they are covered by the DTO routes.
You should also read the routing documentation here, and this post about routing also.
Typo:
You have a typo in your route code. You have an incorrect bracket ( instead of {:
(Permissions}
Should be:
{Permissions}
Metadata
An excellent place to check the service is defined properly is by checking the applications Metadata feature. This is enabled by default, so you can do this by adding /metadata to your server url. i.e.
http://localhost:{port}/metadata
You can see an example metadata page here
Hope that helps.

REST Routing in ServiceStack

I just start to learn REST and ServiceStack and there's something about Route that I just can't quite understand. For example if we take the very basic HelloWorld example from GitHub tutorial and re-write it to return collection of User objects. Here is example:
public User
{
public string Name;
public string Address;
public int Age;
}
// Hello - request object without [Route] attribute
public class Hello
{
public string Name { get; set; }
}
public class HelloResponse
{
public IEnumerable<User> Result {get;set;}
}
public class HelloService : Service
{
public object Any(Hello request)
{
return new HelloResponse { // Collection of User object };
}
}
now everything working right and no problems here. But now I want to add another routing url like: /Hello/{name}/Address
Actually this call (GET) to this url will return a single User selected by Age parameter. How I can do this ? Should I add another Service ? And if the url will be:
/Hello/{name}/{age}/Address
It seems I don't understand something.....
See this earlier answer for details about Routing in ServiceStack. The Smart Routing section in ServiceStack's New API explains further options and different precedence.
There are a few problems with your example. First ServiceStack text serializers only support public properties so you need to change your User Model to use public properties instead of fields, e.g:
public User
{
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
}
Next, Interfaces on DTOs are a bad idea as there's no good reason for it. They're still supported but you can end up with undesirable results. Use a concrete collection like a List<T> which provides more utility, e.g:
public class HelloResponse
{
public List<User> Results { get; set; }
}
Also the routes should match the property names on your DTO exactly, they are case-insensitive when matching against the Request Path, but they need to map to an exact property name, e.g:
/Hello/{Name}/{Age}/Address

Deserializing a json string to C#.net classes using JsonConvert.DeserializeObject (v 4.0.8.14612)

In my web app, I have written some tests to test my deserializing logic that parses a json string in to my C# classes. These tests runs fine on my computer, but they fail on our CI environment with this error message:
Test(s) failed. System.TypeInitializationException : The type initializer for 'Newtonsoft.Json.JsonConvert' threw an exception. ----> System.Security.VerificationException : Operation could destabilize the runtime.
One json string example is this (from the test class):
private const string MatrikkelJson = "{'Gaardsnummer':'9','Bruksnummer':'9','Festenummer':'8','Seksjonsnummer':'8','BlankAllowed':'False','AttrType':'Matrikkel'}";
This string should be deserialized to this class:
public class MatrikkelDTO : AttributeBaseDTO
{
public string Gaardsnummer { get; set; }
public string Bruksnummer { get; set; }
public string Festenummer { get; set; }
public string Seksjonsnummer { get; set; }
}
public class AttributeBaseDTO
{
public bool BlankAllowed { get; set; }
public string AttrType { get; set; }
}
The method that deserializes the json string works like this:
I first deserialize the baseobject to get the AttrType property. Using that information I deserialize the json string to the specific type (I have several classes that inherits from AttributBaseDTO.
public AttributeValidationHandlerResponse ValidateAttribute(string serializedObject)
{
var response = new AttributeValidationHandlerResponse();
response.Result = false;
//hack... this handler gets called when opening newdocument.aspx. don't know why.
if (serializedObject.Contains("function"))
{
response.Message = "";
return response;
}
if (String.IsNullOrEmpty(serializedObject))
{
response.Message = "attributeobject";
return response;
}
var message = "";
var attributeBase = JsonConvert.DeserializeObject<AttributeBaseDTO>(serializedObject);
if (attributeBase.AttrType == "Matrikkel")
{
var attribute = ConvertJsonStringToAttribute<MatrikkelDTO>(serializedObject);
response = ValidateMatrikkel(attribute);
}
return response;
}
internal T ConvertJsonStringToAttribute<T>(string serializedObject)
{
return JsonConvert.DeserializeObject<T>(serializedObject);
}
But I can't figure out why it works on my machine and not on the build server.
I'm using VS 2010, asp.net 4.0, net framework 4.0. Test framework is nunit 2.5.5
Any clues anyone?

Resources