I am binding DataGrid.ItemsSource property to the List<PersonDetails> object. I am getting datas through Silverlight-enabled WCF Service. So the PersonDetails class is implemented in Web Project. Each DataGrid's header text is changing as i want if the class is located in Silverlight project. But then I can not use this class in the web service. The only solution is to add same class in to the both of the projects. But, is there any other way?
The class looks like that:
[DataContract]
public class PersonGeneralDetails
{
// Properties
[DataMember]
[DisplayAttribute(Name = "Sira")]
public int RowNumber { get; set; }
[DataMember]
[DisplayAttribute(Name = "Seriyasi")]
public string SerialNumber { get; set; }
}
It seems attributes aren't generated in web project. I know that I can change header text using DataGrid events. But i want to make it work using attributes.
The problem is the WCF DataContract is an inter-operable mechanism that can be used across languages and platforms.
If you take a look to serialized data generated by the DataContractSerializer (or its code in System.Runtime.Serialization.dll, specifically InternalWriteObjectXyz() methods) you'll see that it merely serializes values into a simple XML message. Nothing related to .NET Framework will be there so all kind of attributes, both custom and compiler generated, will be stripped out and won't even received by the client.
It works creating a copy of your data and sending them from server to client, clients will then create a new class with the same signature. Note: a NEW CLASS with the same signature, NOT JUST A NEW OBJECT of the original class.
Of course there are some workaround for this. You may write your own serializer (see this post on SO for an example) or your own ISerializationSurrogate.
If you can deploy/share your assemblies to your clients you have a nice workaround: just deploy them and DataContractSerializer will build the right object on your clients (exactly the same one you had on the server, with all its attributes). Just remember that:
If custom attributes comes from run-time values (for example because of localization) then they'll be resolved on the client, not on the server (because attributes will be created on the client, their values won't be included in the XML message).
In the client application you need to add a reference to the assembly that contains your types.
When you add your service reference you have to instruct VS to use them (or it'll create proxies), in the Service Reference Settings dialog select Reuse types in referenced assemblies (you can limit this to only assemblies you want to share).
Related
(Edited) -> I have a solution with different projects. It has a strange structure because I'm not an professional software engineer. The solution has three parts: one HMI project (WPF), bussiness project (class library type) and service project (WCF).
In the bussiness project, I do some process that has result which I save in a static class. This results are exposed in the screen by WPF project mentioned previously and now I need to transfer this data by one service placed in the WCF project.
The object is similar to:
[DataContract]
public class ObjectToTransfer
{
[DataMember]
public string ParameterOne = string.Empty;
[DataMember]
public string ParameterTwo = string.Empty;
}
In the other hand, the method that picks up the informtion from static class belonging to bussiness project is like this:
[ServiceBehavior]
public class Service: IService
{
public ObjectToTransfer SendObject()
{
return new ObjectToTransfer{
ParameterOne = BusinessProject.StaticClass.ResultOne,
ParameterTwo = BusinessProject.StaticClass.ResultTwo
};
}
Well, when I consume the service the result is a object with the parameters one and two empty. In additon, when I debug the solution with both projects run, the static class hasn't info in her atributes... It's like whether both projects run independently, in spite of both are under the same solutions..., It's like whether there was no relationship between them. Where is the mistake?
Thank you in advance!
The main thing you will need to do is change the DataContract class to a class with proper getters and setters.
[DataContract]
public class ObjectToTransfer
{
[DataMember]
public string ParameterOne { get; set; }
[DataMember]
public string ParameterTwo { get; set; }
}
The reason this is important is because of the way WCF works when it try to serialize the data from the server to the client. Essentially, the class on the server side schematically matches a generated class on the client. (They share the same class schema.) If there is no proper structure to the class, the data cannot get set. The members are basically read-only.
What you have in your class right now are public member variables, and they are set to always return string.Empty. WCF can't work with that, it is too strict. The server and the client need to be able to read and write to all DataMember properties, so you need the { get; set; }.
Don't forget to refresh your service reference after making this change.
If you need some good resources to learn WCF, check out these videos WCF Tutorial. They are a little dated, but all of the concepts still apply.
This might be late and I am new to WCF service, so I am sharing based on what I have done in my case to share data among different projects.
Background of my project:
I have a WCF service(host), a client and a server project. (A total of 3 different projects.) I will perform the necessary calculation in WCF service. Afterwards, I am suppose to share the result to the client and server. Therefore, there is this variable, variableA, that I have share among the 3 projects.
What I did:
In WCF service, I declare variableA and mark it static:
private **static** string variableA;
Only after I marked variableA as static, then I can see the same variableA across different projects.
I am not sure if this helps but this is what I did in my case.
We are autogenerating our model using EF and when an exposed method uses it, the creation of the proxy client creates the corresponding object type for us.
So, if the WCF has a method signature and type as follows, all the fields are being presented in intellisense when working with said object.
class Thing
{
public int Wanted { get; set; }
public int Unwanted { get; set; }
}
[OperationContract]
public Thing GetSomething() { ... }
This far, we've been using a custom made model using it in our clients namespace definitions. However, it means that we need to manually create a bunch of properties attributed DataMember and the maintenance is a pain.
Is it possible to control which autogenerated fields that are exposed so that when we create a web reference to a service that exposes GetSomething, it only shows those we want? Of course, we still want to build up the model structure on server side using EF so that we simply can regenerate the model when changes to the DB are made.
What about when EF generate your classes, it add DataMember attributes?
Even if you use a custom class for your service, it will be probably based in you EF generated class, so if you use a T4 custom template (.tt file) can save your time. Here you can see if this solution can help you:
Adding [DataMember] [DataContract] attributes in Entity Framework POCO Template
Hope it helps.
I want to have an class like this,
public class Apple
{
public string Size { get; set;}
public string Colour { get; set;}
public string Shape { get; set;}
public int appleId { get; set;}
}
I want to expose that over web services using some web methods like this,
public void AddApple(Apple apple)
{
}
public Apple GetApple(int appleId)
{
}
So when I add a service reference in visual studio to that webservice I get client proxy objects generated for me allowing me to create an Apple on the client side and send that through to the webservice.
Is there a way for me to make one of those properties read only on the client side? I need the setters there so that I can set the values on the server side, but I want to control which data they can update on the client side.
Any ideas?
What I could do is pass in some of the data in the constructor, and only expose getters on the ones I want to be read only, but I want to use an object mapper on the server side. That means ideally I would want to leave the setters there.
In general, you cannot assume control over proxies generated at client side. So correct way would be to ignore values sent by client (or raise exception if he changes those values). The service documentation has to be explicitly mention such things.
Edit:
Yet another work-around would be to divide your data class into two classes - one non-editable by client (say Apple1) and another editable - say Apple2. So now service update method can only accept Apple2 so that client can know looking at generated proxy code what he can change. On server side, you can have Apple1 inherited from Apple2 to have complete data but I believe that proxy generated at client will/can anyway have two different unrelated classes. Perhaps better way in such case would be to have composite full AppleFull containing Apple1 and Apple2.
Please refer to the following question and its answers, I just skimmed through your question but I believe that it is a simillar problem as I faced -
WCF serialization and Value object pattern in Domain Driven Design
Another way to achieve that would be to share the assembly containing the Apple class (but no server side component) between server and client. Make the setters internal and mark the server side assemblies as friends using the InternalsVisibleTo attribute.
This will allow the server to use the setters but not the client.
Background
I have made a Web Service in Visual Studio, and I'm trying to consume it using the automatically generated proxy class. The Web Service returns a class that I have implemented, containing a List.
Question
The proxy class has automatically generated methods to send the SOAP to the web service. It uses the Invoke() method to execute the call, and then casts the result as a DataSet. How can I get this object back into the class I know it is?
I know that I can hand-edit the auto-generated file, but that's not very maintainable, so I don't want to go down that route (any time the Web Service is rebuilt, the changes would have to be made again).
Is there a way to tell the generated class to be more specific, and actually use the correct data type? Or do I have to write a clunky set of deserialisers to get my data back into the correct shape?
Example
One method in my Web Service class:
[WebMethod]
public UpdateList RetrieveUpdates(long sessionID, string configurationVersion, string coreVersion, string researcherDBVersion)
{ ... }
Adding the class as a Web Reference generates the following proxy method:
public DataSet RetrieveUpdates(long sessionID, string configurationVersion, string coreVersion, string researcherDBVersion) {
object[] results = this.Invoke("RetrieveUpdates", new object[] {
sessionID,
configurationVersion,
coreVersion,
researcherDBVersion});
return ((DataSet)(results[0]));
}
The DataSet I receive from this method is always empty (because you can't cast from my class to a DataSet).
Thanks in advance
Since Web References generate partial classes, you should be able to add to your project a partial class extension to the proxy class that reimplements just the method in question (just copy and paste it) but changes the return type (and the name, of course). If the method signature changes, you'll have to update your extension, but at least if that doesn't happen and you regenerate the proxy you won't have to reapply any changes (and you can still use any other generated classes/methods as is).
I've used this approach before to "fix" proxy classes (for instance, to add SOAP headers that aren't defined in the WSDL), and while not ideal, it does work.
Unless your client code knows about your custom class (e.g. has a reference to the assembly) you will not be able to retrieve an object of that type from the service.
It sounds like what you are looking to do is share types across a service layer. In order to do that you will either have to give your client app a copy of the assembly that has the
UpdateList type or you will need to look at something like WCF.
In the past I have needed to create custom SOAP headers in a C# project that was using an imported WSDL web reference. I found a way to do it but I was never happy with it and I have sense wondered if there was a better way. What I did was create a header that derives from SoapHeader:
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://model.test.net")]
[System.Xml.Serialization.XmlRootAttribute("securitytoken", Namespace = "http://model.test.net", IsNullable = false)]
public class SpecialHeader : SoapHeader
{
[System.Xml.Serialization.XmlTextAttribute()]
public string aheadervalue;
}
I then had to modify the code that was generated from the WSDL and add a referen
ce to an instance of the new header and the following before each web call that
I wanted to contain the custom header:
[System.Web.Services.Protocols.SoapHeaderAttribute("instancename", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)]
Where "instancename" is the custom header's instance variable name in the generated class.
This works fine except that any change in the WSDL requires that it all be done over again since it regenerates the class. In other languages the headers can be added outside of the generated code so maybe I'm missing the way that is done in C#. Are there better ways of doing this?
It seems that you are using .Net 2.0 and asmx webservices.
Do you know that there is a framework called WCF (Windows Communication Framework) in .Net 3.0.
I know that it is not easy to migrate to a new framework, but with WCF you get so much.
Furthermore WCf can be used for so much more than WebServices (remoting, msmq and more). It is the framework that Microsoft is betting on for the future.
Ie. manipulation a soap header is done using MessageContracts.
So the answer is that in WCF you can do this with MessageContracts.
Beacuse of generated class is a partial class. You can define it on another file with same namespace and class name (again partial class). Then you can override its virtual methods and define it once.
This prevents further changes on regenerated class doesn't effect the one you wrote.
On new class file you can use "GetWriterForMessage" to override and add new SOAP headers to it.
public partial class SampleService
{
public string MessageID { get; set; }
protected override System.Xml.XmlWriter GetWriterForMessage(System.Web.Services.Protocols.SoapClientMessage message, int bufferSize)
{
message.Headers.Add(new UsernameSoapHeader("Username"));
message.Headers.Add(new PasswordSoapHeader("Password"));
message.Headers.Add(new MessageIDSoapHeader(MessageID));
return base.GetWriterForMessage(message, bufferSize);
}
}
There is a way to do it, sort of; it's not necessarily pretty, and on a very simple web service it may not be worth the effort, but it at least saves you from having to re-add the attributes in when you regenerate the code.
Since the generator generates partial classes, you can:
Add a file to your project that extends the web service class (the one derived from SoapHttpClientProtocol) with another "partial" section (i.e., use the same namespace and name as the generated class, and mark it "partial").
Copy the methods you want to add the headers to (i.e., the same methods you've already been adding the attributes to) out of the generated code and paste them into your extension section.
Rename the methods slightly so that they don't conflict with the ones in the generated code, and change the names that get passed to Invoke to match. (You may have to also tweak the other attributes on the methods to make sure they still map to the proper calls in the WSDL.)
Add the custom header attribute to the renamed methods, and the header instance field to your extension section as well.
Call the renamed versions from your code instead of the original versions.
As long as the method signatures don't change in the WSDL, you won't have to change anything in your code even if you regenerate. (Since you only copy the relatively short method implementations, any other structures from the WSDL will still come out of the generated code, so if they change you'll automatically get the updated versions when you regenerate. Granted, if the WSDL doesn't have any other structures in it, the utility of this is probably somewhat limited.)
It's still not ideal, but short of trying to intercept the raw XML message and put the header in directly (which you could probably do, but it would be nasty), there aren't really any other options that I know of (without moving over to WCF anyway).
I ran into this problem today. I ended creating a class that derives from the autogenerated class and overriding the GetWriterForMessage method to ensure my header was always present. I would update the header value on every call to the method.