Can't transfer list<T> to web service? - c#

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());

Related

Dictionary in wcf

I have an WCF service which contains a method that returns a Dictionary.
The generated method in the proxy class returns ArrayOfKeyValueOfstringstringKeyValueOfstringstring array.
how can i use this method ?
The contract method :
[OperationContract]
Dictionary<string, string> GetESGKeywordQuestion();
In the proxy class i have
ArrayOfKeyValueOfstringstringKeyValueOfstringstring[] GetESGKeywordQuestion()
{
// code
}
The accepted answer in another similar thread reference to a link telling you how to have Dictionary at the client side
in .NET to .NET communication. In other words, poor interoperability if you want your service to be consumed by non-dot-net applications like PHP or Java etc. If you had learned/remember data structure in CS, you know dictionary is implemented through non-linear structure like B-tree, so dictionary is not likely to be included in WSDL because of the complexity and variant. The ArrayOfKeyValueOfstringstringKeyValueOfstringstring structure generated for client is well designed and intended. If you want to see consistency on both side and want interoperability, then don't use Dictionary, instead, use a linear structure such as an array of KeyValuePair.
the generated proxy class seems to be wrong..
Try changing it to return the required Dictionary manually..
Dictionary<string, string> GetESGKeywordQuestion()
{
//code
}
And this should allow you to use you GetESGKeywordQuestion() method from your WCF service

Which C# general structure is recommended to convert a PHP Array to C#?

We are consuming a PHP Web Service.
We have generated the WSDL using Add Web Service Reference in Visual Studio.
The getOurRequest Service method expects a "object" type of input parameter.
The PHP Documentation for this method has the following array declared in PHP.
$getOurRequest =>array(
`aaaa`=> ‘1111’,
`bbbb`=> ‘2222’,
`ccccArray`=> array(
‘cccc3333’
,‘cccc4444‘
),
`ddddArray`=>array(
'dddd5555'
,'dddd6666'
)
);
How do we convert it into C# for use to call the PHP Web Service ?
Any ideas to help with the solution or general serializable structure preferred to pass to the Web Service would be appreciated.
#quetzalcoatl Thank you for the var c# declaration sample. It was helpful but it does not serialize over the service call.
Answering your question directly, the nearest possible structure in C# is a Dictionary, or rather, Dictionary<string, object>
$getOurRequest => array(
`aaaa`=> ‘1111’,
`bbbb`=> ‘2222’,
`ccccArray`=> array( ‘cccc3333’, ‘cccc4444‘ ),
`ddddArray`=>array( 'dddd5555','dddd6666' )
);
I actually do not understand notation $getOurRequest => array(...);. Shouldn't it be plain = instead of => here ?
Either way, in C# analogous variable declaration would be:
var getOurRequest = new Dictionary<string, object>
{
{"aaaa", "1111"},
{"bbbb", "2222"},
{"ccccArray", new string[] { "cccc3333", "cccc4444" } },
{"ddddArray", new string[] { "dddd5555", "dddd6666" } }
);
However, I think that will not solve your problem of sending a HTTP request. For this, you will need HttpWebRequest object, just as Jensen answered, and all the "keys" and "values" from the hashmap/array/dictionary above will need to be provided as the query parameters.
#SOAP: If you can emit WSDL for the web service, then VisualStudio/C#/svcutil can generate a series of proxy classes that will simplify calling the web service very much. If you can do it, drop a note and we'll give you links to how to do that.. or just search the google on "C# call webservice"..
Out of curiosity - if you don't know C# and know PHP well, why do you ask for C# code?
Edit:
In the comments, you've said about "object parameter". In PHP or JS there is a little difference between objects and keyed arrays. In C# it's a big difference because the "dictionary" or any other hashmap will be serialized most probably as a "series of keys and values" - not as an object with fields/keys with values.. If you indeed need to pass an "object", you need to actually have a class and object instance.
//[DataContract] - pick one of them
//[Serializable] - they are required, but without seeing your code, it is hard to tell which one
public class MyWebServiceParameter
{
public string aaaa {get;set;} // those must be properties, not fields
public string bbbb {get;set;}
public string[] ccccArray {get;set;}
public string[] ddddArray {get;set;}
}
....
var tmp = new MyWebServiceParameter
{
aaaa = "1111", bbbb = "2222",
ccccArray = new string[] { "....", "...." },
ddddArray = new string[] { "....", "...." }
};
Just be sure to uncomment one of the "attribtues" - datacontract/serializable. Both of them tell the C# runtime that this class is allowed to be serialized, but each of them comes from a different library or rather, era of networking approach in .Net. In general, each of them could be OK, but one will be better depending on how/what has been generated from the WSDL and what .Net and what extra libraries you are using. If you are using 'state-of-art' .Net, then pick DataContract.
Now, you say you have WSDL? So right-click on your project and choose "Add service reference" or "add web reference" and in the popup dialog enter the URL to your WSDL. The creator should be able to parse it and it will generate a series of support classes for that webservice. Lets say they got called "MyPHPService" and it defines an operation called 'TheServiceMethodName':
var serv = new MyPHPService();
serv.TheServiceMethodName( tmp ); // just pass the object you have created earlier. Or a dictionary, or other..
if your WSDL is OK and if the creator understood it right, then for a call to the SOAP service only those two lines are needed!
I don't know how you're calling your PHP service, so my answer is based on a personal project.
I had no interest into creating a SOAP service and whatnot because C# was not the only language I was communicating with and I wanted to keep things simple. Just use an HttpWebRequest to call a web-server and analyze the page output.
So, I used JSON. There's a powerful library from James Newton-King called Json.NET. It can both convert objects to and from JSON.
On the PHP side, these functions are build into the PHP interpreter: json_encode and json_decode.

stuck up to call the WCF object

This is quite embarrassing ,tried to find the solution by myself but real lack of knowledge i couldn't able to ,so am posting my question here.
my wcf service return this value when i call my service
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetProcessLocationsResponse xmlns="http://tempuri.org/">
<GetProcessLocationsResult >
<a:ProcessLocationData>
<a:Id>1</a:Id>
<a:Name>IL</a:Name>
</a:ProcessLocationData>
<a:ProcessLocationData>
<a:Id>2</a:Id>
<a:Name>MD</a:Name>
</a:ProcessLocationData>
<a:ProcessLocationData>
<a:Id>3</a:Id>
<a:Name>NY</a:Name>
</a:ProcessLocationData>
</GetProcessLocationsResult>
</GetProcessLocationsResponse>
</s:Body>
</s:Envelope>
in my service class i wrote this method
public Array GetProcessLocations()
{
return this.GetSoapServiceClient().GetProcessLocations().ToArray();
}
public List<ProcessLocationData> GetProcessLocationsOnlyName()
{
return this.GetSoapServiceClient().GetProcessLocations().ToList();
}
i call this service in my xyz.class like below
Array GetProcLocation= new GatewayService().GetProcessLocations();
this return whole object like ID and Name
but i was trying to get only the name by calling the "GetProcessLocationsOnlyName" method
i was trying to do like below
array ProcName= ProcessLocationData.Name
should return all the name in the service like (IL,MD,NY) in the array but i couldn't able
to see ProcessLocationData at all.
In another way i was trying to split the array(GetProcLocation) and get only the name and add in to new array ? is that make sense ?
Please some one guide me in to right path.thanks in advance.
I am a little confused about your question.
I do understand that you want to have 2 service methods, both of them returning an array of ProcessLocationData, one returning the list with id and name (GetProcessLocations) and one returning an array of ProcessLocationData with name only (GetProcessLocationsOnlyName).
And your problem is that the client proxy doesn't contain the GetProcessLocationsOnlyName method.
You should make sure that both methods are annotated with OperationContract, otherwise they won't be exposed by your service. You should have this attribute in either your service interface or in service directly. You can see that your service exposes both methods in either wsdl or using the WCF Test Client.
And then you must make sure your client proxy is up to date.
If your client proxy is was generated using visual studio, you should try to update your service reference
If your client proxy is generated using svcutil you must regenerate it manually
Related to your comment, if you want to return only the name field you have the following options.
you can use the same DataContract, that means returning a list of ProcessLocationData and returning an empty Id for each object
you can create a new DataContract that has only one property, Name, and return a list of these objects
My advice is to use the same DataContract and to load only the needed data in the data access method. For example, make a new method GetProcessLocationsName(), that will create your list of ProcessLocationData with only their Name loaded.

ASP.Net Webservice receiving an undefined number of key-value pairs

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.

When do I need a datacontract in WCF and would it be better to use a simple type?

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 !

Categories

Resources