Is there a better way of customizing SOAP headers in C# - c#

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.

Related

DisplayAttribute name property not working in Silverlight

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).

WCF Xml/Json serialization of domain objects, what exactly is getting serialized?

I have a domain class User that has at least 20 properties, and it is from another library so it doesn't have any contract decorations. When I return this over a WCF service as xml or json, its only bringing back like 3 of the properties. I thought maybe it was leaving out collections and whatnot, but even simple fields like Name and Email were not being returned at all.
So I guess my question is, can someone explain what exactly is being serialized and returned over the service? None of the properties are decorated with anything like [DataMember], yet some are serialized and returned while others are not. As I understand, it should automatically serialize all public properties. And on a side thought, if someone could point me in the right direction of how to add these declarations to an existing library to assist in the serialization, it would be appreciated.
UPDATE:
I was looking at the wsdl and found the reference to an xsd file (assumingly generated by the serializer). I noticed that I only has those 3 [mapping]
fields listed. not sure what this is or if I can mess with it.
It turns out that the reason these properties weren't serializing is because they weren't exactly public in that they were read-only. I actually had the properties set to:
public string MyProperty { get; internal set; }
I did this because I do use object initializers in my internal system classes (controller type stuff) and do not wish to allow the consumer to set these properties. I read that you can set them to protected and it will allow it to serialize, however this doesn't work for my implementation.
These are POCO classes, so my solution (albeit not exactly an answer to the problem) was to create DTO classes. Since all of the properties in the DTOs were fully public, all I do is populate those with data from the POCO and return the dto. Everything gets serialized properly.
Take a look at your domain class, and see if it is inheriting from another class. If it is, the User class probably only has the three properties you are seeing.
What I have found to work well is to create a special service model (or view model) as the public data interface, not a direct interface to the domain model. As a benefit, you have much greater control of the data that can be exposed - you limit the risk of unintentional data leakage, as well as optimizing the data sent over the wire.
Best of luck!

Importing data from third party datasource (open architecture design )

How would you design an application (classes, interfaces in class library) in .NET when we have a fixed database design on our side and we need to support imports of data from third party data sources, which will most likely be in XML?
For instance, let us say we have a Products table in our DB which has columns
Id
Title
Description
TaxLevel
Price
and on the other side we have for instance Products:
ProductId
ProdTitle
Text
BasicPrice
Quantity.
Currently I do it like this:
Have the third party XML convert to classes and XSD's and then deserialize its contents into strong typed objects (what we get as a result of this process is classes like ThirdPartyProduct, ThirdPartyClassification, etc.).
Then I have methods like this:
InsertProduct(ThirdPartyProduct newproduct)
I do not use interfaces at the moment but I would like to. What I would like is implement something like
public class Contoso_ProductSynchronization : ProductSynchronization
{
public void InsertProduct(ContosoProduct p)
{
Product product = new Product(); // this is our Entity class
// do the assignments from p to product here
using(SyncEntities db = new SyncEntities())
{
// ....
db.AddToProducts(product);
}
}
// the problem is Product and ContosoProduct have no arhitectural connection right now
// so I cannot do this
public void InsertProduct(ContosoProduct p)
{
Product product = (Product)p;
using(SyncEntities db = new SyncEntities())
{
// ....
db.AddToProducts(product);
}
}
}
where ProductSynchronization will be an interface or abstract class. There will most likely be many implementations of ProductSynchronization. I cannot hardcode the types - classes like ContosoProduct, NorthwindProduct might be created from the third party XML's (so preferably I would continue to use deserialization).
Hopefully someone will understand what I'm trying to explain here. Just imagine you are the seller and you have numerous providers and each one uses their own proprietary XML format. I don't mind the development, which will of course be needed everytime new format appears, because it will only require 10-20 methods to be implemented, I just want the architecture to be open and support that.
In your replies, please focus on design and not so much on data access technologies because most are pretty straightforward to use (if you need to know, EF will be used for interacting with our database).
[EDIT: Design note]
Ok, from a design perspective I would do xslt on the incoming xml to transform it to a unified format. Also very easy to verify the result xml towards a schema.
Using xslt I would stay away from any interface or abstract class, and just have one class implementation in my code, the internal class. It would keep the code base clean, and the xslt's themselves should be pretty short if the data is as simple as you state.
Documenting the transformations can easily be done wherever you have your project documentation.
If you decide you absolutely want to have one class per xml (or if you perhaps got a .net dll instead of xml from one customer), then I would make the proxy class inherit an interface or abstract class (based off your internal class, and implement the mappings per property as needed in the proxy classes. This way you can cast any class to your base/internal class.
But seems to me doing the conversion/mapping in code will make the code design a bit more messy.
[Original Answer]
If I understand you correctly you want to map a ThirdPartyProduct class over to your own internal class.
Initially I am thinking class mapping. Use something like Automapper and configure up the mappings as you create your xml deserializing proxy's. If you make your deserialization end up with the same property names as your internal class, then there's less config to do for the mapper. Convention over Configuration.
I'd like to hear anyones thoughts on going this route.
Another approach would be to add a .ToInternalProduct( ThirdPartyClass ) in a Converter class. And keep adding more as you add more external classes.
The third approach is for XSLT guys. If you love XSLT you could transform the xml into something which can be deserialized into your internal product class.
Which one of these three I'd choose would depend on the skills of the programmer, and who will maintain adding new external classes. The XSLT approach would require no recompiling or compiling of code as new formats arrived. That might be an advantage.

Mixing custom and basic serialization?

I've got a class with well over 100 properties (it's a database mapping class) and one of the properties has to be in a method. In other words this data is not exposed via a property but via methods:
"ABCType GetABC(), SetABC(ABCType value)"
It's all very un-C#-like. I shudder when I see it.
The class needs to be serializable so it can be sent over web services, and the data exposed by the Get/Set methods needs to be serialized too. (It's in a method because of a strange thing the grid I'm using does with reflection; it can't handle objects that contain properties of the same type as the containing object. The problem property stores the original state of the database object in case a revert is required. Inefficient implementation, yes - but I'm unable to re-engineer it.)
My question is this: since only this 1 field needs custom serialization code, I'd like to use custom serialization only for calling GetABC and SetABC, reverting to basic XML serialization for the rest of the class. It'll minimize potential for bugs in my serialization code. Is there a way?
The first thing I'd try is adding a property for serialization, but hiding it from the UI:
[Browsable(false)] // hide in UI
public SomeType ABC {
get {return GetABC();}
set {SetABC(value);}
}
You can't really mix and match serialization unfortunately; once you implement IXmlSerializable, you own everything. If you were using WCF, then DataContractSerialier supports non-public properties for serialization, so you could use:
[DataMember]
private SomeType ABC {
get {return GetABC();}
set {SetABC(value);}
}
but this doesn't apply for "asmx" web-services via XmlSerializer.
Does the [Browsable] trick work at all? Assuming the custom grid uses TypeDescriptor, another option might be to hide it via ICustomTypeDescriptor, but that is a lot of work just to hide a property...

How can I recover a class from the DataSet that it was cast to by the Web Services proxy class?

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.

Categories

Resources