Dynamically created class as DataContract in WCF - c#

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?

Related

How to change WCF service contract which does not effect client?

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.

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.

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

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