i am new but reading some article on wcf i came to know that if you change the ServcieContrcat then you have to change not only the Service end but Clients end too and it's really difficult to manage.
Example 1:
Developer have to create WCF service for Order processing, with following function: GetOrderById, GetOrdersByStatus, SaveOrder
The ServiceContract could looks like following
[ServiceContract]
public interface IOrderService
{
[OperationContract]
Order GetOrderById(int orderId);
[OperationContract]
List<Order> GetOrdersByStatus(OrderStatus orderStatus);
[OperationContract]
void SaveOrder(Order order)
}
after month, for example, project manager say: Ok, our customers need another functions: DeleteOrderById, GetOrdersByCustomerId and don't need GetOrdersByStatus any more, we need GetOrdersByStatusAndCustomerId
Developers have to update ServiceContrcat and update client. As you can see, any changes in the ServiceContrcat is really difficult
so i am looking for best guidance how to develop wcf service which will not create any problem if we extend the functionality or any kind of change but client end will not face any problem. thanks
I had the same problem, basically a perpetual set of changes to methods that would break the interfaces on the clients.
This is what I did: All of my 30+ functions (and the list grows and grows) took strings, ints and bytes() as data types as both input and output parameters, I created a master single endpoint and function that receives, as an input parameter, and sends back as the output, a single simple class. This class, called HostInterface, contains just two parameters, a string (which I use to encapsulate all my strings and ints) and a byte() array (into which I stuff all my binaries)
So, whether a client is calling something simple like Ping() with just one string param, or something complicated like ResumeDownload() with 5 strings, 2 ints and a byte array, all of those parameters get encapsulated in my HostInterface class, the strings and ints into the one String parameters (as XML) and the bytes into the byte field.
When a request is received on the host side here:
Function HostConnect(byval objInbound as HostInterface) as HostInterface
I unpack the string parameter in objInbound, changing the XML into an object, and I unpack the bytes and add them to the byte portion of the same object. Then I check the method name (ping or ResumeDownload) and process accordingly. The diagram below shows the basic idea - all functions operating through a single function that takes and sends the same simple classe as parameters. Thus, my interface never needs to change.
Related
If my contract looks as follows:
[OperationContract]
void DoSomething(int id, out string moreInfo);
this ends up looking like:
string DoSomething(int id);
when you import a web service reference. Is it possible to influence the auto-conversion of the order of the parameters? It was already surprising to find all out-parameters at the beginning of the function signature, but that was still workable, but we'd like void-methods to continue being void-methods. Or is this a SOAP limitation?
It appears to be based on a WSDL limitation:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/48b5992f-f7bd-4b67-8299-514d1780fa9a
WSDL does not show the original method signature; instead, it shows
the input parameters as a group and the output parameters as another
group.
The limitation of not being able to separate return values from out parameters is in the WSDL. But that would mean the limitation of a void method would be part of svcutil.exe I think. There's no reason why there can't be a switch on svcutil to not move the first output to a return value, but that would be a request for a feature on ms connect.
Rather than void, you could return a simple status int or bool if your issue is consistency, but I'm sure that's not a perfect answer if you already have dozens of methods.
I've been working with some form processing providers and they seem to have a generic receiver for key-value pair data. I'm attempting to do this but every data-structure i've tried to use implements an interface and therefore cannot serialize the container for use in the webmethod.
I've even tried using the base 'object' data type - with no success
[WebMethod]
public void processResponse( object lead ){
Dictionary<string, string> DList = (Dictionary<string,string>) lead;
How can I receive an undefined number of key-value pairs using this webservice so i can perform business logic on the received data and intelligently route the data using a unified input method? Statically typed classes will not work in this instance as different types of leads have different numbers of fields/properties.
Switch to WCF, which by default uses the DataContractSerializer class capable of serializing key-value pairs like the Dictionary<T,K>.
The basic structure of your service will be exactly the same and using BasicHttpBinding you have almost the same communication protocol based on Http and Soap. Spend 30 minutes on a WCF tutorial and you'll barely want to go back to old *.asmxes.
What I ended up doing was add a generic handler. I copied the QueryString parameter into a Dictionary and worked with the values from there. It sets a central point of data-collection and I was able to apply my business logic from there -- seems to have suited the purpose of what I wanted.
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.
I am having some trouble designing my WCF service. Bassically I need the service to recieve an XML document. The xml maps to a class that was generated from xsd.exe. I was originally just had this:
public void AddDocument(string xmlString)
Then I would deserialize the xml into the generated class. I was told this is a bad idea because I am doing extra work since wcf will do the serialization for me if I just use the document class as a parameter like this:
public void AddDocument(MyGeneratedClass document)
I'm new to WCF but if I do it this way I thought I would have to create a datacontract for MyGeneratedClass. The generated class is 20,000+ lines so this would take forever.
Do I need a DataContract? Anyway I think I am missing something so I hope this makes sense and if anyone can point me in the right direction I would greatly appreciate it. Thanks!
I would use simple types if your method only requires one or two parameters, and will return only a single simple type value.
As a general rule:
If you need to pass in more than just a few (less than 5) simple types - use some kind of a Request object, otherwise your call gets unwieldy.
If you need to return more than one single simple type value, use a Response object to bundle up those values.
I would try to avoid sending and receiving XML and parse it - try to send back and forth real well structured (data) objects - much easier to deal with and type-safe and all !
I have the same classes on my server and on my web service.
I have the following WebMethod:
[WebMethod]
public int CreateOrder(List<Purchase> p, string username)
{
o.Add(new Order(p,username));
return o.Count;
}
However the following code, run at server:
protected void CartRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
List<Purchase> l = ((List<Purchase>)Session["Cart"]);
if (e.CommandName == "Order")
{
localhost.ValidateService WS = new localhost.ValidateService();
WS.CreateOrder(l, Session["username"].ToString());
}
}
gives the following error: Argument '1': cannot convert from 'System.Collections.Generic.List<Purchase>' to 'localhost.Purchase[]'.
How can I transfer the list<Purchase> object to the web service?
When using web services like that, by default List<T> gets converted into an array (T[]). Convert your list into an array by doing .ToArray() before passing it to the method.
Another option is to change the web service code generation settings to use lists instead of arrays.
It seems you also have duplicate classes, both a local one called Purchase and the one that's generated over the web service, also called Purchase. Even though they have the same name, they're two different types (their namespaces are different). You'll either have to stick to one set of types, or use something like Automapper to map between your two sets of types.
If you're using svcutil to generate the client proxy classes, you can use the collectionType option to force the proxies to use a type other than the default array. This is certainly what gets used for generating proxies to WCF services; I'm not 100% sure if it's used with ASMX services.
Anyway, this is achieved by doing:
svcutil.exe /collectionType:System.Collections.Generic.List`1 [service url]
It is because the webservice uses SOAP to transfer the data, which is an XML protocol.
It knows nothing about .NET lists or many other fancy objects.
So in your case, it is actually transferring an array, and as Matti already said the solution is then simply to use an Array instead.
You can't serialize List<T> into xml, the <T> bit will obviously turn into a badly formed xml tag.
You could make a new object that inherits from List<T>, which will then serialize nicely and go through your web service, this is a minefield of best practice no-nos but you need to compromise sometimes.
localohost.ValidateService is a proxy class, with his own namespaces for classes: then "Order" is not the same as "localhost.Order"
if your calling web service from an other method in ther same web service class,
try this:
tihs.CreateOrder(l, Session["username"].ToString());