I am specifying a Name and a Namespace for every contract in my WCF services, as outlined in Microsoft's Service Versioning guidelines. However, in their example for each contract, Namespace is always suffixed with the Name value, like so:
[DataContract(
Name = "PurchaseOrder",
Namespace = "http://examples.microsoft.com/WCF/2005/10/PurchaseOrder")]
public class PurchaseOrderV1 : IPurchaseOrderV1
{
[DataMember(...)]
public string OrderId {...}
[DataMember(...)]
public string CustomerId {...}
}
Why is PurchaseOrder suffixed on the Namespace? Isn't this redundant? Shouldn't the Namespace be reflective of the whole immutable contract?
If I want my DataContracts and ServiceContracts to be strictly versioned together, shouldn't the Namespace value be http://examples.microsoft.com/WCF/2005/10/ ?
This is natural.
http://examples.microsoft.com/WCF/2005/10/ defines a general product-version-like value. In the same way that you have more fine grained namespaces in your C# code, you would do the same with WCF namespaces.
At the end of the day, namespace is just a namespace and this kind of naming just a convention.
Related
Please have a look at the following question: What's the naming convention for classes in the DataAccess Project?
JDK talks about using Namespaces to separate the Data Logic Layer and the Business Logic Layer and not to use Hungarian notation to name interfaces e.g. IPersonDAL for the data access layer. I have followed the recommendations of this answerer in the code below:
Imports com.app.BusinessLogicLayer.Interfaces
Imports com.app.DataLogicLayer.Interfaces
Namespace BusinessLogicLayer
Public Class Order
Implements com.app.BusinessLogicLayer.Interfaces.IOrder
Public Sub Insert()
Dim IOrder As com.app.DataLogicLayer.Interfaces.IOrder = New com.app.DataLogicLayer.Order
End Sub
End Class
End Namespace
Namespace DataLogicLayer
Public Class Order
Public Sub Insert()
End Sub
End Class
End Namespace
Namespace BusinessLogicLayer.Interfaces
Public Interface IOrder
End Interface
End Namespace
Namespace DataLogicLayer.Interfaces
Public Interface IOrder
End Interface
End Namespace
Classes in the business logic layer e.g. Order implement interfaces (IOrder from Business Logic Layer) and use interfaces (IOrder from Data Logic Layer) i.e. the presentation layer communicates with the Business Logic Layer and the Business Logic Layer communicates with the data logic layer with interfaces. Notice that because of this reason; interfaces have to be fully qualified with the namespace. For this reason; isn't it better to name interfaces using hungarian notation e.g. IPersonBLL and IPersonDAL or am I missing something?
Well, this is a subjective topic, but here goes...
Firstly, avoid abbreviations like DAL. Code Analysis yells about acronyms and abbreviations; you're supposed to write it out. In my experience it's wise advise. Opening up ancient code that's full of abbreviations causes a lot of unnecessary WTF moments (pun intended).
Even when spelling things out, when you have 50 classes sitting in your BusinessLogic folder like this:
Company.Product.BusinessLogic
PersonEntity
OrderEntity
MaterialEntity
EmployeeEntity
CustomerEntity
etc.
My gut tells me it's time to refactor. I feel it's better to move the Entity tag to the namespace, so you have this:
Company.Product.BusinessLogic.Entity
Person
Order
Material
Employee
Customer
etc.
Same things applies to interfaces.
This also makes it easier to refactor. If I want to start calling my Entities "BusinessObjects", I just have to rename the namespace, not the class names and file names.
It can be a pain to qualify your class names, but you normally only have to specify the parent namespace, not fully-qualify them. Resharper -> Cleanup Code does wonders here.
In summary, I would not add Hungarian notation to my interface/class name just to make references easier to deal with.
Update: Example
Data Access Layer:
Namespace Company.Product.DataAccess.Adapter
Public Class Product
End Class
End Namespace
Business Layer:
Imports Company.Product.DataAccess
Namespace Company.Product.BusinessLogic.Entity
Public Class Product
Dim adapter As New Adapter.Product()
End Class
End Namespace
User Interface (ideally your UI should only interact with the business layer, never with the data layer directly):
Imports Company.Product.BusinessLogic
Namespace Company.Product.UserInterface.Webpage
Public Class Product
Dim productEntity As New Entity.Product()
End Class
End Namespace
Notice that because of this reason; interfaces have to be fully qualified with the namespace. For this reason; isn't it better to name interfaces using hungarian notation e.g. IPersonBLL and IPersonDAL or am I missing something?
I see what you are saying, but I don't understand why fully-qualifying the names is bad or why it would be "better" to name the interfaces using "Hungarian" notation. (And I say this as a truly unrepentant fan of Simonyi's apps Hungarian.)
Remember that regardless of the names and locations of the classes/interfaces, the compiler is going to produce the same object code. The apparent nesting level is not going to "slow down" your code to any perceptible degree.
If it really bothers you to type out the names (and Intellisense is of no consolation), you can always use something like a namespace alias with a using directive. But I'd be careful with overusing these—I think it makes the code even harder to read.
Here is the Method signature in the WCF service:
APIMessageList<APISimpleContact> GetMembers(string apiKey, APIContactSearchFilter filter);
APIMessageList inherits from IList. Once I have built a proxy against this WCF service the class name is APIMessageListOfAPISimpleContactjHldnYZV.
Why do I not get: APIMessageListOfAPISimpleContact?
It adds random text to the end of every APIMessageList object in the interface (there are several) They all end with the same few chars - jHldnYZV. I have looked online for possible causes, but I can't find any posts of people having this problem.
This is a purely cosmetic issue but this interface is exposed to our external customers so its appearance is important.
Anybody know why I am getting this problem?
Many thanks
Joe
Your solution will be at http://msdn.microsoft.com/en-us/library/ms731045.aspx. Basically, since you could have multiple "SimpleContract" classes (in different namespaces), WCF will add a disambiguation hash to the end of the contract name, which is what you have in the 8 chars at the end of the contract name. But you can control that, by using the CollectionDataContract and its Name property:
[CollectionDataContract(Name = "APIMessageListOfSimpleContract")]
public class APIMessageList : IList<SimpleContract> { ... }
We had a similar problem while using Generic types for return values. If we are not specifying a concrete type, the default data contract serializer or the WCF serializer is unable to infer the exact type of the returned entity. Hence it generates a random class name for the returned type.
In our project we overcame this problem by building a data contract which was of specific type and returned the same as a result of a WCF operation call.
My guess is that you are using a generic type and the serializer is unable to infer the type of the returned object.
I suggest you create a Data Transfer Object (DTO) and return the same from the WCF service. That should solve your problem.
[DataContract()]
public class Contract
{
.........
Some Properties with DataMembers Attribute.
............
..............
[DataMember(Name = "FirstName")]
public string Name { get; set; }
}
I have above class and I have two web methods (operations)
In 1st web method I want to expose Name as FirstName and in 2nd web method expose Name as LastName.
I don't want to create separate data contracts.
Please tell me how to achieve this?
You can use reflection and change the value of the attribute at runtime depending on which method you in currently. Check out these links on StackOverflow:
How to set attributes values using reflection
Change Attribute's parameter at runtime
But I think the best way would be to either have 2 separate contracts or create a contract with both properties.
You can also implement a surrogate to special-case this type during serialization. As an example, see the Data Contract Surrogate sample.
I write a WCF service for Insert and delete operation here we used generic method but it gives following error
"System.Runtime.Serialization.InvalidDataContractException: Type 'T' cannot be exported as a schema type because it is an open generic type. You can only export a generic type if all its generic parameter types are actual types."
here "EntityBase2" is base class for all entities
[ServiceContract]
[ServiceKnownType(typeof(EntityBase2))]
public interface IBackupUtility
{
[OperationContract]
void Delete<T>(T entity) where T : EntityBase2;
[OperationContract]
void InsertORUpdate<T>(T entity) where T : EntityBase2;
}
Question is how i can expose generic type 'T'?
I think it is imposible, how could it generate the wsdl that way?
You have two options:
You could send the type as a parameter.
If you want to expose crud operations for entities I would recommend to use a code generator, maybe a T4 template for EF.
This post is old indeed, but maybe someone find this solution useful:
WCF and Generics
Answer to this question is both Yes and No. Yes for server prospective and No for client prospective.
We can create a generic Data Contract on server but while using that in any operation contract we have to specify a data type of the generic.
And at client end that data contract will be exposed only as a strongly data type not generic.
[DataContract]
public class MyGenericObject<T>
{
private T _id;
[DataMember]
public T ID
{
get { return _id; }
set { _id = value; }
}
}
[OperationContract]
MyGenericObject<int> GetGenericObject();
This is what we have in Server we can see while using generic data contract we have to specify the type otherwise it’ll give compile time error.
On client what we get from WSDL is a follow:
[DataContract]
public class MyGenericObjectOfint
We can see here what we get from WSDL is not a generic data contract WSDL proxy generate a class with a new name using some convention.
Convention used is
Generic Class Name + "Of" + Type Parameter Name + Hash
Hash is not always generated, it’ll be generated only when there is a chance of name collision.
With the XmlSerializer I can have my members in different namespaces to the parent type.
Can I do the same thing with DataContractSerializer?
I would like the following XML:
<h:Type xmlns:h="http://schemas.e.com/WebServices"
xmlns="http://schemas.e.com/WebServices">
<Member xmlns="http://schemas.e.com/CoreTypes">0</Member>
</h:Type>
Is this possible in with DataContractSerializer?
You can define subdatacontracts in different namespaces and use them as members of another datacontract, but you can't control the individual member names and/or shapes. The DataContractSerializer isn't intended to replace XmlSerializer for fine-grained control of the "shape" of your XML.
While it is true as stated in this answer by nitzmahone that a specific data contract type cannot have declared members in multiple namespaces, it is possible that, in a type hierarchy, derived types can belong to different data contract namespaces than the base types from which they inherit. When this happens, each member will be serialized into the namespace in which it is declared. By constructing an appropriate type hierarchy, XML entities with members in disparate namespaces can be (de)serialized by DataContractSerializer.
The specific rules are as follows:
If a data contract type is a part of an inheritance hierarchy, data members of its base types are always first in the order.1
Data members are serialized into the data contract namespace of the data member type in which they are declared.
The root namespace of a data contract type is the namespace of its most derived type.
XML elements are (de)serialized in the order specified by Data Member Order. DataContractSerializer does not allow for data members to be freely reordered during deserialization.2
Collections have their own rules as specified in Collection Types in Data Contracts; this answer does not apply to them.
Thus the XML in the question can be consumed by DerivedType in the following type hierarchy:
[DataContract(Name = "Base", Namespace = "http://schemas.e.com/CoreTypes")]
public class BaseType
{
[DataMember]
public int Member { get; set; }
}
[DataContract(Name = "Type", Namespace = "http://schemas.e.com/WebServices")]
public class DerivedType : BaseType
{
}
And, in general, any sequence of XML elements in any sequence of namespace(s) can be obtained by applying the rules above to construct an appropriate type hierarchy, offering a workaround that meets the requirement of deserializing elements in different namespaces.
Of course, such a hierarchy might be inconvenient for other reasons, in which case the preferred data model types can be replaced with DTOs by using the data contract surrogate mechanism.
1 Data Member Order.
2 Data Member Order and XML Deserialization