stuck up to call the WCF object - c#

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.

Related

Sharing the same message contract for two actions

My services are supposed to parse a SOAP request for an action ILogging/LogMessage which has 'log-entry' as the root element inside the SOAP body. For that, I have a method LogMessage that expects parameter of type LogMessageRequest.
LogMessageRequest has the MessageContract attribute set with WrapperName as log-entry:
[MessageContract(WrapperName = "log-entry")]
public class LogMessageRequest
{
...
}
I am also expecting another SOAP request for an action ILogging/LogException with 'log-entry' as root element in the SOAP body. For this, there's a method LogException and a param of type LogExceptionRequest.
The difference between both the SOAP actions is that a child element 'message' inside 'log-entry' is different (for LogMessage, 'message' is a string and for exception, it's a complex entity).
The issue:
Since both LogMessageRequest and LogExceptionRequest have the same wrapper names (log-entry), I'm getting an exception originating from LogException saying "log-entry has already been exported by LogMessage".
I tried using the same request class for both and have the 'message' of type object. But that refuses to work.
Any pointers? (there's no scope of changing the SOAP request by the way).
While there might be a way to match the different schemas with a common interface, I suggest a more prudent approach: build an adapter over one of the service interfaces to match the interface of the other.
This way, the ugliness is isolated and the application will only have to work with only one service interface.
I don't believe you can implement this using MessageContract/data contract from your description. You might be able to do it with XmlSerializer attributes, but it sounds like you will need to use the Message class in the operation contract and peek at the message xml to figure out which one it is. Can you post the relevant bits of the WSDL/SOAP definitions?

Dynamically created class as DataContract in WCF

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?

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.

Is this a namespacing problem?

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.

Can't transfer list<T> to web 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());

Categories

Resources