I am experiencing a strange behavior with very basic web service development. This question might be dumb but I think someone would be able to explain this observation.
I am developing a web service with a web method, MyWebMethod
MyWebMethod(MyEnum Param, .....)
Where,
public enum MyEnum : int
{
Type_1 =1;
Type_2 =2;
Type_3 =3;
}
Now I am using my client to communicate with this service but for every request type, Type_1, Type_2 etc the service captures it as Type_1. As an example, if I create a break point at MyWebMethod in my web service, I see Type_1 as param1 type. I guess this is a problem with Namespacing. I cannot see any other defects on the code. Any Idea based on the experiences?
When enum is serialized, only its string representation is transferred through wire (names), not the values. I believe thats the reason you are getting the wrong values.
Check out this 2 articles for more info
WebServices_and_Enums
Using enum in web service parameter
If this is a WCF web service and a .NET 2.0 client generated with wsdl.exe for each value type in the method signature there will be a boolean parameter added called XXXSpecified which you need to set to true. Check this blog post for more details.
I guess your enum does not need to inherit from int. You are providing name and value in the enumeration, that should suffice. I am assuming all your code is .NET 2.0. As test , return an enumeration value from the webservice. Just to make sure XML Serialization is working as expected when the service is hit directly by the browser.
Related
I have a rest web service, which suppose has a method
int foo(Mytype x)
it has many clients, i wanted to add a parameter to to Mytype and change how foo behaves, As this is a restful service so all clients also implement there version of Mytype any ideas how to accomplish this without breaking any clients?
Have u considered versioning? E.g. server/ver2/foo
I think your only other option would be to implement the new functionality, such that it is not required, e.g.
foo (MyType myType) {
if (myType.newField exists) {
// do new stuff
}
}
One final note, i would recommend combining both approaches, which will ensure that foo is backwards compatible.
I think the safest way would be to go with versioning.
You could provide a new version for MyType which can be handled using the MIME type description in the Accept and Content-Type headers, i.e. like so:
application/json+foo;application,v=2
Another possibility would be to handle the version via the URI/URL, i.e.
https://api.yourhost.com/v2/MyType
Like Damo already said you then have to handle the use of the different resource representations on the server.
I added a int to my POST request and it didn't break anything. So looks like adding a parameter to rest service request class is not really "Breaking Changes" but removing one will certainly break the clients.
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 have an ASMX WebService that I am testing, and on most of the methods I am able to use the test form just fine for testing. I do however have one method for which the test form says:
The test form is only available for requests from the local machine.
This method is declared exactly the same way the other methods, but it does have a noticeably longer parameter list (most of these methods only have 2 or 3 params):
[WebMethod]
public ActionSuccessResponse makeDestinationRequest(String ownerID, String destinationRegion, String destinationCountry, DateTime desiredTravelDate1, String destinationCity = "", DateTime? desiredTravelDate2 = null, DateTime? desiredTravelDate3 = null) {
Any ideas? I'm stumped.
If you must use the older ASMX files, you should test them with something like SOAPUI.
The built-in test page only handles very basic parameter entry (and probably has a limit on the number of parameters before it gives up). Basically don't use it.
As it turns out, the problem was actually occurring due to the DateTime typed parameters in the method definition. Web Services should use primitive data types for all parameters to allow for compatibility with other languages.
Is there any way to return an array of objects of type DynamicClass from WCF method?
I'm using Dynamic Linq Library in my WCF service, so as to select columns of database table , as per the request from clients. The client code should look like this:
//client side code
string whereClause = "FeatureId >= 6 and FeatureId <= 180";
string selectClause = "New(FeatureName as Name, FeatureId as Id)";
client.RequestAsync("Feature", "FeatureDB", whereClause, selectClause);
Feature is the name of the table from which I want to select two columns only, viz. FeatureName and FeatureId, satisfying the condition in the where clause.
Here, the problem is that the query runs fine on the server, but WCF is unable to send it back to the client. My guess is that the dynamically created class which defines only the selected columns is not declared DataContract, so WCF isn't able to work with it.
So any solution to this problem?
Or any alternative? The goal is, I don't want to return all columns of the database table, because I don't need all of them on the client side. So I don't see any point sending all columns back to the client, who will discard it anyway.
You may be able to work around this by using Reflection to decorate your fields with the appropriate attributes, however this may still present an issue for any client process that consumes your WCF service, as the generated section of your service contract will be non-deterministic, i.e. xs:any in the schema.
Better to try and strongly type your WCF contracts wherever possible.
Have you considered implementing a WCF Data Service?
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());