WCF single service multiple contracts and generics, possible?
Can I have a single service with multiple endpoints and multiple contracts using generics. I am running into an issue开发者_如何学Python where the metadata cannot be created (It hink it may just be a config issue and not sure what my base host address would need to look like):
namespace WCFSingleService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract]
public interface ISingleService<T>
{
[OperationContract]
T GetData(T item);
}
}
namespace WCFSingleService
{
[ServiceContract(Name = "User")]
public interface IUserSingleService: ISingleService<User>
{
}
}
namespace WCFSingleService
{
[ServiceContract(Name = "Some")]
public interface ISomeSingleService: ISingleService<Some>
{
}
}
public partial class SingleService : IUserSingleService
{
public User GetData(User item)
{
//Do something
}
}
public partial class SingleService : ISomeSingleService
{
public Some GetData(Some item)
{
//Do something
}
}
Is this possible and what would the configuration for this service look like? Also, would I be able to consume the service from, say, an AJAX client? I guess I would since I am not trying to pass in a type to the contract and each contract would have its own endpoint, right? Thanks!
Here is my current configuration:
<system.serviceModel>
<services>
<service name="WCFSingleService.SingleService" behaviorConfiguration="WCFSingleService.ServiceBehavior">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8732/Design_Time_Addresses/WCFSingleService/SingleService" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="User" binding="wsHttpBinding" contract="WCFSingleService.IUserSingleService"/>
<endpoint address="Some" binding="wsHttpBinding" contract="WCFSingleService.ISomeSingleService"/>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCFSingleService.ServiceBehavior">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
UPDATE: Well, I was tring to figure out why my servcie wasn;t wroking, once I turned debugging on, that opened up the error dorr. DUH! Anyway, the issue I was having had to do with the same method name being created for both services. So, does anyone know of a way to have WCF rename the method names if multiple services impelement the same interface? Is there a decoration I can put on a method inside one of the implementations to make it appear different?
yes you can have single service with multiple contracts, you have to set ConfigurationName on your service interface.
You need to declare your interface like this
Namespace ServiceNameSpace
<System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0"), _
System.ServiceModel.ServiceContractAttribute([Namespace]:="whatever namespace you like", ConfigurationName:="ServiceContract1")> _
Public Interface ServiceContract1
<System.ServiceModel.OperationContractAttribute(Action:="Service Action"), _
System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults:=True)> _
Function ServiceFunction1(ByVal var As Class1) As Class1
End Interface
<System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0"), _
System.ServiceModel.ServiceContractAttribute([Namespace]:="temp namespace", ConfigurationName:="ServiceContract2")> _
Public Interface ServiceContract2
<System.ServiceModel.OperationContractAttribute(Action:="Service Action"), _
System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults:=True)> _
Function function2(ByVal var As Class2) As Class2
End INterface
End Namespace
THen you need to have a class that would actually have the implemetation of both the service contracts that you have exposed
namespace ServiceNameSpace
Public Class ServiceImplementationCLass Implements ServiceContract1, ServiceContract2
Public Function ServiceFunction1(byval var as class1) as class1
'Do whatever you want to
end Function
Public Function function2(byval var as class2) as class2
'Do whatever you want to
end Function
end namespace
end Class
And at last just configure the service like below
<system.serviceModel>
<services>
<service name="ServiceNameSpace.ServiceImplementationCLass" behaviorConfiguration="ServiceBehavior">
<endpoint address="" binding="basicHttpBinding" contract="ServiceContract1" />
<endpoint address="" binding="basicHttpBinding" contract="ServiceContract2" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
The code above is in VB.NET if you want I can provide you with C# code also,
I hope my solution would help you out.
I'm gonna have to with No.
I tried to make a service return an interface because it could return several types. In the end it responded like returning Object would (badly).
Instead I implemented different callback functions for each possible returned type:
[ServiceContract(CallbackContract=typeof(IClientFeedback))]
public interface IDataService
{
[OperationContract]
void GetItem(string entryID);
}
[ServiceContract]
public interface IClientFeedback
{
[OperationContract(IsOneWay = true)]
void ReturnMailMessage(MailMessage msg);
[OperationContract(IsOneWay = true)]
void ReturnContact(Contact cont);
}
I know it's not quite the same, but if interfaces don't work, I'd think that generics are even less likely.
I figured out pretty much what I wanted to accomplish. Basically, I could still setup my code to use generics while having one service. I got the idea for the single service here. I then realized that I needed to specify the ServiceContract on the partial class SingleService (Not the interfaces themselves) and decorate my implemented methods with the OperationContract(Name="TheExposedNameOfTheMethod"). Here is some of the code:
public interface ISingleService<T>
{
//[OperationContract]
T GetData(T item);
}
public interface IUserSingleService: ISingleService<User>
{
}
public interface IOtherSingleService: ISingleService<Other>
{
}
[ServiceContract]
public partial class SingleService : IUserSingleService
{
[OperationContract(Name = "GetDataUser")]
public User GetData(User item)
{
switch(item.MessageCommand)
{
case "Create":
//do stuff to for a User create
break;
case "Update":
//do stuff to for a User update
break;
case "Delete":
//do stuff to for a User Delete
break;
}
return item;
}
}
//You only need to specifc the ServiceContract attribute in one of the partial classes
public partial class SingleService : IOtherSingleService
{
[OperationContract(Name = "GetDataOther")]
public Other GetData(Other item)
{
...do something
return item;
}
}
Here is what the endpoint would look like:
<endpoint binding="basicHttpBinding" name="TheService"
contract="SingleService" />
精彩评论