How to use XmlAttributeOverrides with WCF - c#

I have a WCF service using basicHttpBinding. On a service method I have a class that is returned, for this class I need to dynamically / programmatically exclude properties and change property names for the XML. This needs to be done both in the WSDL and when the service method is called.
I have searched for the best solution and it seems that I will need to (1) use the XmlAttributeOverrides with the XmlSerializer or (2) implement the IXmlSerializable on the class that needs to be customized. Or there may be a better solution altogether. I know that Property Name + "Specified" can be added to the class and then those properties can be excluded. However, this does not exclude in the WSDL and this doesn't solve the property renaming issue.
Why do I want this? Because of globalization and customization of our application. There are many properties that are built into our application that may be renamed or hidden entirely from users of the application.
After MUCH research I the best option is to swap out the WCF serializer with my own custom serializer. However, I never found good examples of how to do this for a custom class that would use the XmlSerializer. Also I'm not sure how I would pass in the XmlAttributeOverrides for a specific class.
Also, this might not be the case for others who want this same functionality but in my application I only need to initialize the values once for the lifetime of the app. Too bad C# doesn't allow static readonly variables to be used with attributes.
Here is an simple example of a class:
public Customer
{
public string Address1
{
get;
set;
}
public string Address2
{
get;
set;
}
public string Zipcode
{
get;
set;
}
}
In this example I would like to for certain installations of the application use PostalCode instead of Zipcode and hide the Address2 property.
Your help is very much appreciated.
Thanks,
Tyler

There are many properties that are built into our application that may be renamed or hidden entirely from users of the application.
A standard approach is to create a special Data Transfer Object (DTO). Or several.

I know this seems like a bit of a cop out, but since your object property names are dynamic why not just use property bagging instead of doing this XMLSerializer shuffle?

Related

set a value to the attribute at run time

I have a namespace that contains some classes, one of the classes I'm working on contains properties, where each proprty has an attribute associated with it, as the follwing
namespace Local.Business
{
[DynamoDBTable("myTableName")]
public class Business
{
[DynamoDBHashKey("PK")]
public string MunId {get; set;}
[DynamoDBRangeKey("SK")]
public string Id {get; set;}
[DynamoDBProperty("Dba")]
public string Dba {get; set;}
}
}
the string "myTableName" need to be determined at runtime(by calling a function or reading it from other class's property)
How can I achieve that, please?
What you are trying to do is inherently flawed. You kinda can ish change attributes sort of, sometimes, but there's a good chance that whatever is consuming the attributes won't see the change, which makes it entirely pointless.
Basically: you need to find another way of reconfiguring DynamoDB at runtime. This isn't it.
For the "kinda can ish":
you can materialize attributes, and if they're mutable, change the copies you have; but when other code materializes the attributes, they'll get different unrelated versions, which will not have any changes you have made
there is an API that supports this concept (System.ComponentModel), but: most attribute consumers do not use that API - it is mostly just UI binding tools (think PropertyGrid, DataGridView, etc) that would take any notice of it - because they are expecting to work with things like DataTable that require a different approach to metadata and reflection
Set the table name value to empty string in the class file:
[DynamoDBTable("")]
During runtime, use the overloaded functions on DynamoDBMapper to pass DynamoDBMapperConfig configured with TableNameOverride
Actually I deleted the table property and I gave the table name in the query
dynamoDBOperationConfig = new DynamoDBOperationConfig();
dynamoDBOperationConfig.OverrideTableName = "tableName";
string munId = "1";
var search = dynamoDBcontext.QueryAsync<Business>(munId, dynamoDBOperationConfig);
and It works fine, thank you all guys for helping

JSON serialization with odd characters

There is an application that was originally written in Ruby on Rails that provides API services to several mobile applications; management has decided to add the functionality of the RoR service to the main .NET-based project. OK, no big deal, we'll just duplicate the service calls in WebAPI right? How difficult can it be?
Apparently somebody on the Ruby side thought it would be a swell idea to put extra characters into the api response objects. I'm seeing things like:
{
...
{"enabled?":true}
...
}
...so here I am, shaking my head at this, and hoping there is a technique to serialize .NET objects into JSON where variable names have question marks and whatnot. Is there a way to do this, or are we going to have to build custom serializers for each of these objects? Changing the mobile apps to consume more platform-friendly JSON is really not desirable at this point. We use JSON.Net, but if there's another way to do this, it'd be OK.
In your c# object, give your property a valid name (such as Enabled in this case) and then specify the JSON property name in the Name property of a DataMember attribute, or the PropertyName property of a JsonProperty attribute:
[DataContract]
public class MyClass
{
[DataMember(Name="enabled?")]
public bool Enabled { get; set; }
}
Or
public class MyClass
{
[JsonProperty("enabled?")]
public bool Enabled { get; set; }
}
If you use DataMemberAttribute, don't forget to add the DataContract attribute, and that data contract serialization is opt-in, so you'll need to add DataMember to all the attributes you want to serialize. Having done so, however, you'll gain compatibility with the DataContractSerializers, which might be useful down the road.

Using DescriptionAttribute in Domain Entities

I am currently developing a system that needs to expose some of its metadata/documentation at runtime. I know there are methods of using XML Comments and bringing that data back into the app via homegrown Reflection extension methods.
I feel it might be easier to use the description attribute from the System.ComponentModel namespace (but located in System assembly). This way I and other developers would be able use regular reflection to get the Description of fields. I much rather use this than using a custom attribute. What are the downsides to this approach?
Example:
public Customer
{
public int Id { get; set; }
[Description("The common friendly name used for the customer.")]
public string Name { get; set; }
[Description("The name used for this customer in the existing Oracle ERP system.")]
public string ErpName { get; set; }
}
I am doing the exact same thing (with ERP software no less!) and have encountered no drawbacks. One thing you may consider a drawback in your situation depending on your architecture is that many documentation tools are directly or indirectly based on XML comments. They will likely not be able to pick up description attributes. But in our architecture, the Description attribute code is not actually the master/source of the documentation. We have a database of MetaData that defines and describes every property. We can generate XML comments and Description attributes from that same source. Actually in our case, we do not generate the XML comments at all, but instead directly generate the XML file that would normally be generated by the XML comments directly. That's the file used by the documentation tools we use. You could probably write a simple utility to extract the description attributes into a similar XML file if you want to use documentation tools that rely on the xml file output by xml comments, if it can't accept the Describiton attribute directly.

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

Add property to POCO class at runtime

I selected ServiceStack OrmLite for my project which is a pure Data-Oriented application. I am willing to allow the end user to create his own Object Types defined in an XML format that will be used to generate classes at runtime using CodeDOM.
I will be also defining some "system" objects required by the application (i.e. User) but I cannot foresee all the properties the end user will use and therefore I am looking for a way to allow extending the classes I create in design time. Sample bellow
public class User
{
public Guid Uid { get; set; }
public String Username { get; set; }
public String Password { get; set; }
}
The end user wants to have an Email and an Address. He should be able to add the 2 properties to the upper class and the whole class will be (which still can be used by OrmLite, since it allows overwriting :
public class User
{
public Guid Uid { get; set; }
public String Username { get; set; }
public String Password { get; set; }
public String Email{ get; set; }
public String Address { get; set; }
}
I know that there might be a risk of doing so to crash the system (if the class is already instantiated) so I am looking for the best way to avoid this issue and mimic the need I have.
It seems that there are two parts to what you're doing here. You need to create types dynamically to support the additional properties. You also need to ensure that you never end up with duplicate types in your AppDomain, i.e. two different definitions of User.
Runtime type generation
The various suggestions already given handle how to create the types. In one project, we had something similar. We created a base class that had the core properties and a dictionary to store the 'extension' properties. Then we used Reflection.Emit to create a derived type that had the desired properties. Each property definition simply read from or wrote to the dictionary in the base class. Since Reflection.Emit entails writing low-level IL code, it seems complex at first. We wrote some sample derived classes in another class library and compiled them. These were examples of what we'd actually need to achieve at runtime. Then we used ildasm.exe to see what code the compiler produced. This made it quite easy to work out how we could generate the same code at runtime.
Avoiding namespace collisions
Your second challenge is to avoid having duplicate type names. We appended a guid (with invalid characters removed) to the name of each generated type to make sure this never happened. Easy fix, though I don't know whether you could get away with that with your ORM.
If this is server code, you also need to consider the fact that assemblies are never unloaded in .NET. So if you're repeatedly generating new types at runtime, your process will continue to grow. The same will happen in client code, but this may be less of an issue if you don't expect the process to run for an extended period of time.
I said assemblies are not unloaded; however, you can unload an entire AppDomain. So if this is server code you could have the entire operation run in its own appdomain, then tear it down afterwards to ensure that the dynamically created types are unloaded.
Check out the ExpandoObject, which provides dynamic language support for doing something like this. You can use it to add additional properties to your POCO's at runtime. Here's a link on using .NET's DLR features: http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject%28v=vs.100%29.aspx
Why not use a key value pair for all its properties, or at least the dynamic ones?
http://msdn.microsoft.com/en-us/library/system.collections.hashtable.aspx
You can do it the way you're describing with Reflection but it will take a performance hit, this way will allow removal of properties also.
The project I'm currently working on has a similar requirement. We have a system already in production and had a client request addition fields.
We solved this by simply adding a CustomFields property to our model.
public class Model: IHasId<Guid>
{
[PrimaryKey]
[Index(Unique = true)]
public Guid Id { get; set; }
// Other Fields...
/// <summary>
/// A store of extra fields not required by the data model.
/// </summary>
public Dictionary<string, object> CustomFields { get; set; }
}
We've been using this for a few weeks with no issues.
An additional benefit we found from this was that each row could have its own custom fields so we could handle them on a per record basis instead of requiring them for every record.

Categories

Resources