I want to be able to send two different JSON messages on one queue. How do I, in C#, determine what type of message was received so that I can deserialize the message to the proper object? Should I use a message header or create another queue? A queue per message type seems excessive to me. Thanks!
Extra Details:
I have a Windows service that processes "runs". A run ID is assigned by another system and the ID is dropped on a queue. My service picks up the ID and starts work. An object is created for each run. Right now, if I want to cancel work, I have to stop the service. But, that stops all work. I wanted to add a CancelRun type method, but all I need to the run ID. So, I could use the exact same JSON (so same class). Two queues wouldn't be horrible, but I thought it might be clever to add the type or something to a custom header.
Here's what I went with. I like this technique because I'm not adding stuff to the JSON that isn't part of the model.
IBasicProperties props = model.CreateBasicProperties();
props.Headers = new Dictionary<string, object>();
props.Headers.Add("RequestType", "CancelRunRequest");
Then, on the receiving side, I do this (I'm raising an event with a custom EventArg obj):
// Raise message received event
var args = new MessageReceivedArgs();
args.CorrelationId = response.BasicProperties.CorrelationId;
args.Message = Encoding.UTF8.GetString(response.Body);
args.Exchange = response.Exchange;
args.RoutingKey = response.RoutingKey;
if (response.BasicProperties.Headers != null && response.BasicProperties.Headers.ContainsKey("RequestType"))
{
args.RequestType = Encoding.UTF8.GetString((byte[])response.BasicProperties.Headers["RequestType"]);
}
MessageReceived(this, args);
model.BasicAck(response.DeliveryTag, false);
Elsewhere in the project:
private void NewRunIdReceived(object p, MessageReceivedArgs e)
{
if(e.RequestType.ToUpper() == "CANCELRUNREQUEST")
{
// This is a cancellation request
CancelRun(e);
}
else
{
// Default to startrun request for backwards compatibility.
StartRun(e);
}
}
If an order or receiving and processing of these messages is not an issue I would like to suggest using separate queues for each type, it's not a problem for rabbit to handle tons of queues.
If not, the order is crucial for you, you can put marker in header of the message defining it's type, however this will bind your Business Logic with transportation layer. In case you will want to change the transportation layer later in your application, you will have to adopt this section of code to keep it work. Instead of this you can make some sort of wrapper for both of those object types which hides the internal content, looks the same and can desalinize itself in type it contains.
Adding runtime type information as suggested by sphair works, but I dislike doing that since you loose the portability value of having a weak type. You might also consider having the deserialized C# object be generic enough to handle all the flavors, and then branch from there.
You can add all of them into array and then deserialise based on type, you will have to add type property manually, or you could create Object IHaveType and then inherit from it in objects that are being used, but that's a horrible way to do this.
ObjectType1 : HaveType
public class HaveType { public string Type { get { this.GetType(); }}}
Json
[{Type: 'ObjectType1', ...[other object stuff]},{Type : 'ObjectType2',...}]
JSON does not say what a type it was serialized from, unless the serializer itself adds some information to the JSON.
You could add some structure to the JSON so you are able to deduct the type.
Related
I have a small WinRT client app to my online service (Azure Web Service). The server sends a JSON encoded object with (with potential additional metadata) to the client and the client's responsibility would be to deserialize this data properly into classes and forward it to appropriate handlers.
Currently, the objects received can be deserialized with a simple
TodoItem todo = JsonConvert.DeserializeObject<TodoItem>(message.Content);
However, there can be multiple types of items received. So what I am currently thinking is this:
I include the type info in the header serverside, such as "Content-Object: TodoItem"
I define attributes to TodoItem on the client side (see below)
Upon receiving a message from the server, I find the class using the attribute I defined.
I call the deserialization method with the resolved type
(Example of the attribute mentioned in 2.)
[BackendObjectType="TodoItem"]
public class TodoItem
My problem with this approach however is the Type to Generics in the deserialization as I can't call:
Type t = ResolveType(message);
JsonConvert.DeserializeObject<t>(message.Content);
I tried finding some solutions to this and getting method info for the DeserializeObject and calling it using reflection seemed to be the way to go. However, GetMethod() does not exist in WinRT and I was not able to find an alternative I could use to retrieve the generic version of the DeserializeObject (as fetching by the name gives me the non-generic overload). I don't mind using reflection and GetMethod as I can cache (?) the methods and call them every time a message is received without having to resolve it every time.
So how do I achieve the latter part and/or is there another way to approach this?
Alright, I feel like this was not really a problem at all to begin with as I discovered the DeserializeObject(string, Type, JsonSerializerSettings) overload for the method. It works splendidly. However, I would still like to hear some feedback on the approach. Do you think using attributes as a way to resolve the type names is reasonable or are there better ways? I don't want to use the class names directly though, because I don't want to risk any sort of man-in-the-middle things be able to initialize whatever.
Just a few minutes ago we have posted the alternative way to do what you want. Please look here, if you will have any questions feel free to ask:
Prblem in Deserialization of JSON
Try this
http://json2csharp.com/
Put your Json string here it will generate a class
then
public static T DeserializeFromJson<T>(string json)
{
T deserializedProduct = JsonConvert.DeserializeObject<T>(json);
return deserializedProduct;
}
var container = DeserializeFromJson<ClassName>(JsonString);
I am building a library which can parse complex files into a datamodel. Inside the library during parsing and during some other operations on the data structure I am building certain messages might occur (info, warnings, errors).
I need a way for the user of the library to fetch those messages. All stuff I am thinking about boils down to some static Event or a static list of those messages. But I want each object of the datastructure to have its own message queue.
An example:
class Program
{
static void Main(string[] args)
{
CalibData cd1 = new CalibData();
cd1.LoadFile(#"C:\tmp\file.ext");
var messageList = cd1.GetMessages();
cd1.DoOtherStuff();
CalibData cd2 = new CalibData();
cd2.LoadFile(#"C:\tmp\file2.ext");
cd2.LoadFile(#"C:\tmp\file3.ext2");
messageList = cd1.GetMessages(); //Do other stuff could have produced new Messages
var messageList2 = cd2.GetMessages();
}
}
Do you have any suggestions on how to implement such behavoir? I need something which is globally accessibly inside each instance, but each instance has another global messenger.
Additional Information:
Internall I am using an ANTLR Parser which generates a lot of objects (50.000+). Once the datastructure is created a lot of crossreferences are being set on the objects, etc. My main problem is, that I either have to create a static member to handle this, or from LoadFile() pass a messenger very deep into my function calls of the parser, cross referencing etc. In my opionion both is a rather bad choice. Changing the design is not an option since there is more to my problem. The datastructure is stored in 2 files (1 file = description, other file = data). So I can call something like
CalibData cd = new CalibData();
cd.LoadFile("description file"); //after this call the datastructure is built, but it hasn't got any value data yet
cd.LoadFile("data file") //now the structure also has value data
cd.ClearData();
cd.LoadFile("yet another data file"); //same structure different data
It looks like your LoadFile method currently doesn't return anything - why not make it return a data structure containing the errors, warnings etc? No need for anything global or static - or even persistent. Just the result of a method call.
In fact, I'd probably change this slightly so that a separate class (rather than the model itself) was responsible for loading, and the LoadFile call would return a result containing:
Information and errors
The resulting model object
That way any time you have a model you know it contains actual data - rather than it being "ready to load" as it were.
Let's say we have a business object, let's call it a Foo, which contains an ordered list of Bars. We pass this Foo around as XML.
We have a class which deserializes a Foo XML node (FooXMLDeserializer) which itself uses a class which deserializes the child Bar XML nodes (BarXMLDeserializer).
Now, I'm adding some functionality to the BarXMLDeserializer that maintains some state such that if FooXMLDeserializer is called on two separate Foo nodes without reseting the BarXMLDeserializer's state, the results may be invalid. BarXMLDeserializer does not know when it has processed the final Bar in a Foo.
Is there some way that I can design the BarXMLDeserializer class to communicate to developers working on consuming classes that it has state and must be reset for each Foo?
Further info:
My change solves a minor enough problem in our code that I won't be able to convince my manager to let me spend X days redesigning the whole system to nicely handle this case.
If it matters, BarXMLDeserializer keeps is state in a BarStateTracker class which is internal to it.
Programming in C#, but looking for a more general solution.
Thanks.
Expose your serializer only as a static method:
// no public constructor, etc
var deserializer = BarXMLDeserializer.CreateNew();
Then, when you have finished deserializing data, mark a field in your object. If the field is set, throw an exception if the same instance is used to deserialize more data when the deserialize method is called.
if(IsInstanceExhausted)
throw new InvalidOperationException("You must use a fresh instance.");
They'll figure it out after their first exception. In addition, mark your class as IDisposable so that code naturally uses using statements:
using(var deserializer = BarXMLDeserializer.CreateNew())
{
}
The list goes on of additional ways. ALTERNATIVELY, you could simply design your Deserializer to clear it's state or reset after a deserialization attempt, or to clear the state at the beginning of a deserialization attempt.
One particular aspect of some code I've written is causing me minor headaches, I can't pinpoint the reason - all the type checking and casting is making me feel uneasy. The code works as it is right now. I'd like to know wether or not there's a better way to handle the type-specific aspects of the code.
I'm using a non-generified, object-returning JSON parser which makes me go through various incantations in my generified code.
The signature of the parse method is public static object JsonDecode(string json) The runtime type of the object it returns can be ArrayList, Hashtable, double or string. I'm calling the JsonDecode method on a Twitter Search response, which returns the result tweets as a top level object of the form:
{"results":[
{"text":"#twitterapi http:\/\/tinyurl.com\/ctrefg",
"to_user_id":396524,
"to_user":"TwitterAPI",
"from_user":"jkoum",
"metadata":
{
"result_type":"popular",
"recent_retweets": 109
}, ... MORE-DATA ...}
The context in which I'm using the JsonDecode(string json) method is
private IList<Tweet> searchResult = new List<Tweet>();
var jsonDecoded = JSON.JsonDecode(responseString);
IList rawTweets =
(IList)((Hashtable)jsonDecoded)["results"];
foreach (var rawTweet in rawTweets)
{
searchResult.Add(new Tweet((Hashtable) rawTweet));
}
The Tweet class does its own type checking and casting
class Tweet : DynamicObject
{
private IDictionary<string, string> stringValues =
new Dictionary<string, string>();
private IDictionary<string, double> numberValues =
new Dictionary<string, double>();
public Tweet(Hashtable rawTweet)
{
FlattenJSON(rawTweet);
}
//flatten input and assign to correct map/dictionary based on JSON value type
private void FlattenJSON(Hashtable table)
{
foreach (DictionaryEntry entry in table)
{
//this code is not handling the case, that the Tweet contains a JSON array
//not necessary as of now: this code is intended for demo purposes in a talk
//I'm giving on Friday 2010-06-25
if (entry.Value is String)
stringValues.Add((string)entry.Key, (string)entry.Value);
else if (entry.Value is Double)
numberValues.Add((string)entry.Key, (double)entry.Value);
else if (entry.Value is Hashtable)
FlattenJSON((Hashtable)entry.Value);
}
}
...
}
Am I handling the type checks in the FlattenJSON method correctly? What about the casts in the code snippet building the IList and constructing the searchResult IList<Tweet>? Would you have written the code in a different way?
As a side note, the complete code is available via http://github.com/codesurgeon/pop-tweets The code is intended for a demo in a talk that I'll be giving on selected .NET features. The Tweet class is a DynamicObject and it overrides TryGetMember, see full listing on github.
Thank you ;)
P.S.: [FYI] This is a more specific version of my previous post, requesting a general code review https://stackoverflow.com/questions/3113293/how-to-be-a-good-c-citizen-review-requested-for-c-4-0-dynamic-sample-code
A few things stand out to me:
First, you should so some argument validation. Check to see if "table" is null before you start using it. Otherwise, you will get an unhandled NullReferenceException and it will confuse your consumer.
Next, does this actually work? The "is" keyword (I thought) only worked with reference types, and double is a value type. I would assume that this wouldn't work and you'd need to instead do a double.TryParse().
Lastly, there is a lot of casting on-the-fly. When you are interacting with a 3rd-party API, I would argue that you should have an interface where you convert from "their weird stuff" to "your clean stuff". So even if the API is messy and difficult, clean it up and present it to your consumer in the proper way. Don't propogate the bad design. In other words, as a consuming developer, I would want some obvious and clean data structures to work with. Like: foreach(Tweet tweet in Twitter.GetTweets()) or something. I don't care that you happen to use json right now. That implementation should be be invisible to me.
Hope that helps...
I would not do it like that.
First of all, your tweet class is not a real object, it's a data container. You could just continue to work with the jsonDecoded variable, since your tweet class doesn't add any functionality or abstraction (other than abstracting away the JSON decoder).
How I would do it:
Create POCOs which holds the information: Tweet and a Metadata class.
Create a serializer which takes the JSON string and returns the Tweet class
By dividing it into two steps and also creating real classes you will have it much easier in the future. Please read about Single Responsibility.
I develop winforms app. One of my forms accepts user input and calls a web service to add the input into the DB. The input must be unique, however I have no way of knowing if it is unique in the client side. I send the input to the WS and it is responsible of either adding it to the DB or informing the client that the input already exists.
What is the correct way to implement that?
Should I make two calls to the WS, one to know if it is unique and one to insert into the DB? I sense synchronization issues + two round trips across boundary.
Should I return an enum, ValueNotUnique and ValueInsertedSuccessfully?
Or perhaps throw an exception? That sounds not performance wise, plus I don't like using exceptions for things I already know that might not work.
Is there a nice design to this mess? Help appreciated, thanks in advance!
I would probably do something like this:
define an enumeration of result values; ValueAlreadyExists, ValueInserted etc.
define a return object type that would include
the result of the operation, as that enum type
if the value already existed - possibly something like an ID or even some of the data
if the value was inserted successfully, the new ID
So you'd have:
public enum OpResult
{
ValueInserted,
ValueAlreadyExists
}
and a result type:
public class ResponseType
{
public OpResult Result { get; set; }
public int UniqueID { get; set; }
}
With this approach, you can easily
extend the enumeration and add more possible outcomes for your operation
extend the response type and add more information if you need it
Your web method can return a custom class that has multiple properties. Web services are not required to only return primitive or atomic types. Mark the custom class Serializable and ensure that any properties are also serializeable, etc.
Alternatively you can throw an exception if you consider the cases where you didn't insert to be errors and catch the exception in the calling application.
I would do it the following way:
You send the request to the server. There you check if the value is correct. If it is correct you make an insert and send a valid result back to your client. If it is not correct you send an error message back.