WCF Event Order - c#

I need to hook into an event in a slightly unusual manner in WCF.
I'm passing a model from the client to the server, and I need access to that model:
After the model has been created but
Before the incoming data has actually been deserialized to that model
The reason is I actually have deserialization events that are conditional, and ideally I want that condition itself to be a property on the object; thus, I'd have the pattern:
create object->set property->deserialize the rest of the object based
on that property
Is there an event in WCF that I can hook into for this? I've got an attribute set up that hooks into the "IOperationBehavior" and "IParameterInspector" set up, but those don't (as far as I can tell) have an action that hooks in between the creation and deserialization events.
Alternatively, I'd be fine with a way of modifying the data coming in off the wire and explicitly adding that property into the incoming data, provided I could guarantee that it would be the first property deserialized.
Any ideas?
[Edit]
Minor note, I'm using JSON as the data transport here, not that that should really have an impact on the final solution.

You could theoretically implement a nested envelope, whereby the actual data passed to your WCF service consists of a class (the envelope) which has the data needed to determine how to deserialize and a byte array which consists of the real data in a serialized format. Then you could manage the deserialization of the byte array manually.
Seems there is probably a better way, but I've done similar things and they work.
EDIT: Perhaps an IDispatchMessageInspector is the right place to hook?

Related

Problems trying to pre-load objects to a text file for faster load times

I have been working on a Windows Form Control project to import into a 3rd party client software using their supplied SDK. The custom control written by yet another company I am trying to load requires sign on to a server before displaying information, which can take 20-30 seconds. In order to speed things up I had the idea to pre-load information needed by the control to a text file. Since it is not a known type it is throwing errors when trying to serialize the class.
I have a Dictionary I am using to reference back to the proper ICamera class. If I change "cam" from an ICamera type to a string, for example "cam.GetLiveURL()". It writes the text file without issue. This is the code I am using to populate the Dictionary.
foreach (ICamera cam in _adapter.Cameras())
{
OCCamera.Add(cam.GetDisplayName(), cam);
}
I have tried XMLSerializer, and it seems it has difficulty dealing with a Dictionary.
I have tried BinaryFormatter and get the error:
Type 'OCAdapter.OCCamera' in Assembly 'OCAdapter.dll' in not marked as serializable.
I have tried DataContractSerializer and get the error:
Type 'OCAdapter.OCCamera' with data contract name
'OCCamera:http://schemas.datacontract.org/2004/07/OCAdapter' is not
expected. Consider using a DataContractResolver or add ant types not
known statically to the list of known types - for example, by using
the KnownTypeAttribute attribute or by adding the to the list of known
types passed to DataContractSerializer.
I have tried playing around with the DataContractResolver and can not seem to get it to work, I do not understand it at all.
The code I am using for the BinaryFormatter and DataContractSerializer are straight from MSDN or elsewhere, and test fine without the custom type.
Maybe there is a better way to handle all this, and I am missing it. I am not opposed to ditching the Dictionary route for something else, or I can rewrite any amount of other code to make this work.
Mistake 1: trying to serialize your implementation rather than the *data.
Mistake 2: using BinaryFormatter... just about ever (except maybe AppDomain marshalling)
My advice: create a simple model ("DTO" model) that just represents the data you need, but not in terms of your specific implementation (no OCAdapter.OCCamera etc). You can construct this DTO model in whatever way is convenient for whatever serialization library you like. I'm partial to protobuf-net, but many others exist. Then map to/from your DTO model and your implementation model.
Advantages:
it'll work
changes to the implementation don't impact the data; it only impacts the mapping code
you can use just about any serializer you want
you can version the data sensibly

Deserialize binary data without knowing the exact type written

I've encountered a problem where a small number of data objects stored using a BinaryFormatter are coming back with parameters missing (null/default).
I'd like to know if the missing items were saved as null, or if the objects that were serialized were changed from the versions in source control and then reverted before a code commit (eg int numDogs vs unsigned int dogCount).
The former would represent a serious bug in the data validation code ran before the serialization was done; while the latter is just junk data in a test DB and ignorable.
Since the BinaryFormatter is able to get everything else out when a member is changed, added, or removed I assume it's writing objects in a form similar to a key value store. Is there any way to get a human readable representation of it, without having to try and guess the exact details of the object that was serialized?
If you implement ISerializable on your objects, you can have a look at what's been serialized by trying to deserialize.
You will need to add a constructor with the same signature as ISerializable.GetObjectData - this is where deserialization occurs.

How do I serialize a dynamic object?

I want to make a Configuration Data Manager. This would allow multiple services to store and access configuration data that is common to all of them.
For the purposes of the Manager, I've decided to create a configuration class object - basically what every configuration data entry would look like:
Name, type, and value.
In the object these would all be strings that discribe the configuration data object itself. Once it has gotten this data from its database as strings, it would put it into this configuration object.
Then, I want it to send it through WCF to its destination. BUT, I don't want to send a serialized version of the configuration object, but rather a serialized version of the object discribed by the configuration object.
The reason I'd like to do this is so that
The Data Manager does not need to know anything about the configuration data.
So I can add configuration objects easily without changing the service. Of course, I should be able to do all of the CRUD operations, not just read.
Summary:
Input: string of name, type and value
Output: Serialized output of the object; the object itself is "type name = value"
Questions:
Is this a good method for storing and accessing the data?
How can I/can I serialize in this manner?
What would the function prototype of a getConfigurationData method look like?
I have decided to go in a different direction, thanks for the help.
Is this a good method for storing and accessing the data?
That is difficult to answer, the best I can give you is both a "yes" and a "No". Yes, It's not a bad idea to isolate the serialization/rehydration of this data.... and No, I don't really care much for the way you describe doing it. I'm not sure I would want it stored in text unless I plan on editing it by hand, and if I'm editing it by hand, I'm not sure I'd want it in a database. It could be done; just not sure you're really on the right track yet.
How can I/can I serialize in this manner?
Don't build your own, never that. Use a well-known format that already exists. Either XML or JSON will serve for hand-editable, or there are several binary formats (BSON, protobuffers) if you do not need to be able to edit it.
What would the function prototype of a getConfigurationData method look like?
I would first break-down the 'general' aka common configuration into a seperate call from the service specific configuration. This enables getConfigurationData to simply return a rich type for common information. Then either add a extra param and property for service specific data, or add another method. As an example:
[DataContract]
public class ConfigurationInfo
{
[DataMember]
public string Foo;
...
// This string is a json/xml blob specific to the 'svcType' parameter
[DataMember]
public string ServiceConfig;
}
[DataContract]
public interface IServiceHost
{
ConfigurationInfo GetConfigurationData(string svcType);
}
Obviously you place a little burden on the caller to parse the 'ServiceConfig'; however, your server can treat it as an opaque string value. It's only job is to associate it with the appropriate svcType and store/fetch the correct value.

Serializing encapsulated lists in a Web Service

I have a class MyClass containing a private List<MySecondClass> myList. The list is exposed through a getter as follows:
public IEnumerable<MySecondClass> MyList
{
get { return myList.Select(a => a); }
}
The list is modified through public AddItem(MySecondClass itemToAdd) and ClearItems() methods. I believe that this is a properly encapsulated list.
The problem lies in that I need to pass an object of type MyClass (containing myList) via SOAP to a web service, which fills myList (using the AddItem() method), and then returns the object.
However, when the webmethod returns the class, after serialization myList is empty. I am suspecting this is because I do not have a setter for myList, which is causing the list not to be set during serialization.
Is this a good assumption, or am I way off? If the problem is what I think it is, is there a way to allow for the list to be successfully passed from the webmethod without breaking encapsulation (I do not want to expose a generic list)?
Without trying this directly myself, I believe that you could definitely be correct.
serialization in .NET makes utilizing read only properties a fun circus.because the .net default serialization process requires a setter property in order to "deserialize" the object. Without a setter property the serialization piece will still work allowing you to serialize to a drive or across the network. But, it is the deserialization process that will fail which could definitely be why your collection is empty. Im just amazed it doesn't error out to be honest.
Have you tried to add a simple setter just to verify that this is in fact the issue just so that we know with 100% certainty that this is the problem before working to solve it.
While I never really solved the initial problem, what I did do to get it working was simplify the data that was being passed to the web method. Instead of passing an entire object to the web method, I instead passed a unique identifier. The webmethod then returns the list I need, and I handle actually adding the items in this list to the object client-side.
The XML Serializer used by ASMX services only serializes public read/write properties.

WCF contract for Field level update

I'm developing an application that does some CRUD operations through a WCF service. The read method returns a complete entity, the update is performed through a legacy system, and only the changed values should be updated.
What is the best way to design the data contract for this scenario without simply sending a dictionary of key-value pairs?
The only other thing I can think of is to make your component durable - i.e. persist its state to a file or database. That way, on the update you can compare the previous state to the state being passed in. I'm not sure that's a good way to go since it will introduce more overhead than just passing in the key-value pairs.
From the outside it might look more CRUDy or whatever, but from a practical standpoint you may be better off just passing some indication as to which values changed.
In case it helps, not sure exactly what you're looking for though ...
In the update request, only act upon fields that are not null.
In addition wrap any non-nullable types in a nullable structure.
As an example ...
Update( Nullable<int> orderNumber,
Nullable<DateTime> orderDate,
Nullable<bool> isComplete )
{
if( orderNumber != null )
databaseRecord.OrderNumber = orderNumber;
if( orderDate != null )
databaseRecord.OrderDate = orderDate;
if( isComplete != null )
databaseRecord.IsComplete = isComplete;
}
the best way to do this is with property dictionary, just represent your entities as dictionary of property name and value.
save all changes in some list and pass a partial dictionary with all changed properties.
i think this is best design,
if u wanna avoid this design, send entire entity with some list of changed properties.
(to save transport u can put null on other properties)
if u don't wanna change the service contract signature u can push the names of modified properties on the header
I had two ideas of how to achieve this;
Have the client send both the original entity, and the changed entity in full, the service would then figure out what properties were changed.
Use a pattern similar to Nullable, lets call it Modified with an IsModified flag and a NewValue property of type T. Each property of the DataContract would be of this type, the service can check the IsModified flag when performing the update.
The legacy sytem we use has an api that accepts String.Empty to identify unmodified fields, a '?' character is used to indicate an update to an empty string. I really don't like this, the user of the api is forced to read the documentation, and if you actually want to store a '?' you can't. I want our webservice api to be more explicit.
You can use DataSet to keep your changes. Call your record as DataSet then assign some values to the record. DataSet.Tables[0].GetChanges() will give you the columns which were changed.
You could leave the data contract alone and update your service contract. Just represent the required fields for the method as properties within the service contract. Any consuming application using the service will have to be updated if the service contact changes, but the consuming application will know what is required to successfully update the data.
There are positives and negatives to this method, but I use it when a method I am writing doesn't require the full data contract.
--Edited for a spelling error--
Looking at your requirements and statements, i've made a few assumptions before starting to write my vision on a possible solution:
You are using the same class for retrieving (return value type of "read" operation) and updating an item (input parameter type of "update" operation) in your WCF service.
Your current problem of implementation is how to use the original class (not a dictionary) AND still be able to determine 'what has changed compared to the read' when you get the "Update" operation called on your WCF service
You are writing both the server and client. Both are written using the MS .Net framework.
If this is true, the problem lies in the Update method missing information. The information required is 'has changed' which could be inferred if a 2nd state is present to compare against or should already be present along side the state to update in the back-end.
Since you only have the 'back-end state' (without flags) when the client posts its data to the WCF service, how should we determine what did change? Obviously, we want to prevent another 'read' roundtrip to get the current server state and start comparing.
Sending the original & changed state from the client to the server is a possible but heavy solution. Next to that, the client isn't interrested in this information, the server is.
Adding this all up makes my guess is that changing the type of the 'Update' operation input parameter is the easiest way to go. Create a decorator class that adds 'dirty bit' behavior to the original entity. Use this new class as input parameter for your "Update" operation. You then will have the availability in the server to check this dirty bit next to the full state send by the client. The major change on the client side is that the object needed for the 'Update' operation is no longer the same as the one provided by the 'Read' method. To eleviate this pain, i would probably create a decorator class which added the required 'dirty bit' handling. This only requires the object instanciation to change, while maintaining the interface signature for the client (very little code changes).

Categories

Resources