I sure I'm missing something simple and obvious here but I can't find the answer:
I have a WCF service that returns Widgets. Widgets are defined in the service.
In my client program I also define and use Widgets. The Widget definition in the client and the service are identical. The problem is that Widgets returned by the service are ServiceReference1.Widget but the client program expects MyProgram.Widget. How do I get the client program to work with the service Widgets?
On the service:
[DataContract]
public class Widget
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public decimal Price { get; set; }
}
public class Service1
{
public async Task<IEnumerable<Widget>> GetAllWidgets()
{
await Task.Delay(Util.GetDelay(), CancellationToken.None);
return GetAllWidgets();
}
}
In the client program I also define Widgets. I call the service to get some:
public async Task<List<Widget>> GetWidgetsAsync() // expects MyProgram.Widget
{
using (ServiceReference1.Service1Client client =
new ServiceReference1.Service1Client())
{
var response = await client.GetAllProductsAsync();
return response; // gets ServiceReference1.Widget
}
}
Do I need to iterate through the response and build a duplicate set of client Widgets? Or do I define Widgets in a separate library and reference it from both client and server?
Thanks
The best way is to put the passed type (DTOs) and Service Interfaces into a shared library and reference it in both projects.
I'm also guessing you are autogenerating the client based on the service layer. Don't do this for the shared DLL scenario. See this article:
http://blog.walteralmeida.com/2010/08/wcf-tips-and-tricks-share-types-between-server-and-client.html
Related
I have a clean architecture project that provide micro services, one of which is to access Agresso ERP web services.
https://***************/service.svc
it provide many services
https://**/service.svc?FooService/Foo
https://**/service.svc?BooService/Boo
each of which has it's own service reference(connected service), and each of which has many methods.
each call to any of the end point you need to pass credentials with it.
var fooSoapClient = new FooSoapClient();
var credentials = new WSCredentials
{
Username = "fakeuser",
Password = "fakepassword",
Client = "fakeclient",
};
var result = fooSoapClient.GetFoosAsync(Foo filter,true,
credentials );
(P.S) credential class exist in all entities
namespace Foo1NS
{
public partial class WSCredentials : object
{
public string Username {get;set;}
public string Client {get;set;}
public string Password {get;set;}
}
}
namespace Foo2NS
{
public partial class WSCredentials : object
{
public string Username {get;set;}
public string Client {get;set;}
public string Password {get;set;}
}
}
i can access all end points with no problem.
I have the following Questions:
Is there a generic solution i can follow for not to Fall in DRY?
is there a design pattern that best target this issue?
Here is what I've done in the past, it fits in well into Dependency Injection/containers if you use that as well. The key thing here is to define an single interface that all services will implement. Your code that uses this should only be using the interface.
Each class should implement an interface you define, e.g. IWebServiceOperations
public interface IWebServiceOperations
{
WebServiceOperationResult GetFooAsync(WebServiceOperationRequest request);
}
I'll leave you to figure out the classes WebServiceOperationResult/Request, they just hold your request/response variables, including credentials.
Then each webservice you need to implement is done in a separate class. You also dictate in the constructor what type of implementation this is (FooSoap1 vs FooSoap2) e.g.
public class FooSoapClient : BaseClient, IWebServiceOperations
{
public FooSoapClient() : base(Clients.FooSoap1)
public GetFooAsync(...)
{
...
}
}
public class BaseClient
{
private readonly eFooServiceType _serviceType;
public eFooServiceType ServiceType {
get{
return _serviceType;
}
}
protected BaseClient(eFooServiceType service)
{
_serviceType = service;
}
}
Now you should have a bunch of class references. Either your DI container can resolve these for you, based on the service type you want, or you could add them to a Dictionary, so if you wanted to operate against FooSoap1, you'd do...
var fooSoapClient1 = myServices[Clients.FooSoap1];
await fooSoapClient1.GetFooAsync(...)
I have a WCF Service with the following operation contract:
[OperationContract]
Response SearchEntities(Query query);
This operation takes a request that contains a specified Entity like so:
[DataContract]
public class Query
{
[DataMember]
public string SearchTerm { get; set; }
[DataMember]
public string Entity { get; set; }
[DataMember]
public bool ExactMatch { get; set; }
}
Based on the value contained within the Entity property, one the following properties is populated within this response:
[DataContract]
public class Response
{
[DataMember]
public List<Asset> Assets { get; set; }
[DataMember]
public List<Stage> Stages { get; set; }
[DataMember]
public List<Sector> Sectors { get; set; }
}
Terrible design, I know! However. I am using Autofac.Wcf as my service factory to inject dependencies. Normally I would use a common Interface and Generics to determine a service to use based on the Entity value like so:
public interface IEntitySearch<T>
{
Response Search(Query query);
}
The above interface would have several implementations for each of the Lists within the response. Using a design pattern such as a service location I could determine which service to use (all of which inherit from IEntitySearch<T>, something like:
public IEntitySearch ResolveSearcher(Query query)
{
switch(query.Entity)
{
case "Assets":
return _container.Resolve<AssetSearch>();
case "Stages":
return _container.Resolve<StageSearch>();
default:
throw new NotSupportedException();
}
}
While this works, a more elegant solution (I believe) would be to customize the Autofac container per request for this particular operation, depending on the data contained within the request.
IE: Before the WCF pipe line sends the request to the service implementation, is it possible to examine the request data and customize how the container resolves dependencies. That way I can avoid exposing dependency resolution within my service layer.
Is this possible?
If another DI library other than Autofac has a solution for this, I will happily change our DI framework.
Thanks.
I haven't personally tried this but I think a direction you can go down is to combine:
Using OperationContext.Current to get the current request message data.
Specifying a custom IServiceImplementationDataProvider for Autofac that tells Autofac which WCF interface to host for that request.
Using a lambda registration for your service implementation to switch the backing service based on OperationContext.Current.
You can see two examples of the IServiceImplementationDataProvider by looking at the DefaultServiceImplementationProvider - the one that works in Autofac WCF hosting by default; andMultitenantServiceImplementationDataProvider, which is more about generating a proxy to enable multitenant WCF hosting.
While neither of these use OperationContext.Current to determine the actual backing service, you can build on the ideas:
Look at the Autofac.Multitenant.Wcf implementation. You may be able to use it as-is. The point of the instance data provider there is that WCF grabs on to the concrete type of the service being hosted and if you try to swap types out from under it, you get errors. The multitenant support fools WCF by creating a proxy type and your implementation type can be swapped out under the proxy. Note the MultitenantServiceImplementationDataProvider doesn't actually tie anything to a tenant or tenant ID; it's only about that proxy.
In your .svc file specify a service interface rather than any individual concrete implementation since you'll be swapping out the implementation.
Use a lambda registration to figure out your implementation.
Make sure your service is InstanceContextMode.PerCall to ensure things get swapped out on a per request basis.
The registration might look something like this:
builder.Register(ctx => {
var context = OperationContext.Current;
var type = DetermineTypeFromContext(context);
return ctx.Resolve(type);
}).As<IMyServiceInterface>();
The Autofac WCF and Autofac Multitenant section on WCF may also help.
In my opinion you're trying to move your problem just to another place. Why would making decision based on request at low-level WCF is better than switch in SearchEntities method? It's much worse ;-)
I would consider to use IEntitySearch factory/provider e.q.IEntitySearchProvider (it's not so much better but always).
public interface IEntitySearch
{
bool IsMatchQuery(Query query);
Response Search(Query query);
}
// without service locator
public class EntitySearchProvider : IEntitySearchProvider
{
private readonly IEnumerable<IEntitySearch> _searchers;
public EntitySearchProvider(IEnumerable<IEntitySearch> searchers)
{
_searchers = searchers;
}
public IEntitySearch GetSearcher(Query query)
{
// last registered
return _searchers.LastOrDefault(i=>i.IsMatchQuery(query))
?? throw new NotSupportedException();
}
}
or
public interface IEntitySearchProvider
{
IEntitySearch GetSearcher(Query query);
}
public class EntitySearchProvider : IEntitySearchProvider
{
private readonly IComponentContext _container;
public EntitySearchProvider(IComponentContext container)
{
_container = container;
}
public IEntitySearch GetSearcher(Query query)
{
switch(query.Entity)
{
case "Assets":
return _container.Resolve<AssetSearch>();
case "Stages":
return _container.Resolve<StageSearch>();
default:
throw new NotSupportedException();
}
}
}
with
public class WcfService
{
private readonly IEntitySearchProvider _provider;
public WcfService(IEntitySearchProvider provider)
{
_provider = provider;
}
public Response SearchEntities(Query query)
{
var searcher = _provider.GetSearcher(query);
return searcher.Search(query);
}
}
I am trying to add a new service to ServiceStack, but it is not being recognized, and my routes are not showing up in the metadata.
This is my service:
public class EventService : Service
{
public object Post(EventRequest event_request)
{
return new EventResponse() {
name = "FirstEvent"
}
}
}
public class EventRequest
{
public int event_id { get; set; }
}
[Route("/event", "POST")]
public class EventResponse {
public string name { get; set; }
}
I have even explicitly referenced the EventService in AppHost, even though they are in the same assembly. I am just adding a service to the basic service tutorial code, and my service is defined within the same namespace as the HelloService.
public AppHost() //Tell ServiceStack the name and where to find your web services
: base("StarterTemplate ASP.NET Host", typeof(HelloService).Assembly, typeof(EventService).Assembly) { }
I have also tried stopping and starting the IIS express service
What am I missing?
It won't work because you have applied your [Route] to the wrong class. You need to have the route defined on the request DTO not the response DTO. So you should define it this way:
[Route("/event", "POST")]
public class EventRequest : IReturn<EventResponse>
{
public int event_id { get; set; }
}
Your action method should define the return type too, rather than type object:
public class EventService : Service
{
public EventResponse Post(EventRequest event_request)
{
return new EventResponse() {
name = "FirstEvent"
}
}
}
You aren't getting metadata defined just now because there are no methods that are using your response EventResponse as a request DTO. So just a really minor thing causing your issue.
Old service assembly in bin:
Remove the SecondWbService.dll from your bin. This is an older service that is being loaded instead of MainWebService.dll - the one that you are actually editing and wanting to run. Because ServiceStack doesn't allow more than one AppHost, WebActivator is finding the older DLL and running it first, thus your service is hidden. After deleting that DLL, rerun the solution and it should be picked up correctly. You can confirm this by adding a breakpoint:
public AppHost() //Tell ServiceStack the name and where to find your web services
: base("StarterTemplate ASP.NET Host", typeof(HelloService).Assembly, typeof(EventService).Assembly)
{ // BREAKPOINT HERE, confirm the assembly is loaded
}
The metadata and service should then work correctly.
How to inherit all DTO resource in one service?.
Say for example ,
I Have Resource Class :
[RestService("/getstudentname", "GET,POST,PUT,OPTIONS")]
public class RestResourcename
{
public string Name { get; set; }
}
[RestService("/getstudentID", "GET,POST,PUT,OPTIONS")]
public class CNextRestResourceid
{
public string Name { get; set; }
}
I have my Service Class :
1.How to inherit another DTO Class in this Service ????????
2.Do i need to create seperate class for this ?????
public class CnextRestService : RestServiceBase<RestResourcename>
{
public override object OnGet(RestResourcename request)
{
return request;
}
}
Please suggest me on this issues.......
You can implement multiple HTTP Verbs on the same Resource (aka Request) DTO in the same web service, e.g:
public class CustomersService : Service
{
object Get(GetCustomer request){...}
object Post(CreateCustomer request){...}
object Put(UpdateCustomer request){...}
object Delete(DeleteCustomer request){...}
}
This allows you to provide multiple implementations for the following HTTP actions:
GET /customers
GET /customers/1
POST /customers
PUT /customers/1
DELETE /customers/1
Although if you use SOAP you're limited to 1 RPC method for each web service since SOAP only supports HTTP POST.
The best way to do this is to inherit from Service and implement the Any() method which will be called regardless of which HTTP Verb or endpoint was used to invoke the service.
I have Googled and read for hours now and I can't find anyone that deals with my specific scenario...
I want to use interfaces in my WCF service contracts to loosely couple the service from the classes used on each end of the wire. This will enable us to have a low-level assembly that contains just the Service and Data Contracts (just interfaces) that we can hand to a consultant. On their end of the wire they can instantiate their data classes that implement our Data Contract interface, send it over the wire to us, and our WCF service will then translate/cast/whatever that incoming data into our version of a data class that implements the same interface.
Here's an example. IDataContract contains the bare information I want to transmit over the wire. The endpoints and other WCF-specific config are all default stuff (my problems may lie in that, so I can include more of it if that's where I need to change things).
EDIT: I've included more of the code and renamed a couple classes to help it be less confusing. The Name & Namespace additions to the DataContractAttributes, as well as the two sections in the config files are new additions based on information from this blog post. If I switch to an abstract base class instead of an interface, it works. However, I'd like to get this working with an interface if possible.
Shared library (my code, shared with client authors):
public interface IDataContract
{
string MyProperty { get; set; }
}
[ServiceContract]
public interface ITestService
{
[OperationContract]
IDataContract TestSharedInterface(IDataContract clientData);
}
Client code (their's):
[DataContract(Name = "IDataContract", Namespace = "http://services.sliderhouserules.com")]
public class ClientDataClass : IDataContract
{
[DataMember]
public string MyProperty { get; set; }
}
private static void CallTestSharedInterface()
{
EndpointAddress address = new EndpointAddress("http://localhost/ServiceContractsTest.WcfService/TestService.svc");
ChannelFactory<ITestService> factory = new ChannelFactory<ITestService>("ITestService", address);
ITestService proxy = factory.CreateChannel();
((IClientChannel)proxy).Open();
IDataContract clientData = new ClientDataClass() { MyProperty = "client data" };
IDataContract serverData = proxy.TestSharedInterface(clientData);
MessageBox.Show(serverData.MyProperty);
}
Client config:
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="ServiceContractsTest.Contracts.DataContracts.IDataContract, ServiceContractsTest.Contracts">
<knownType type="ServiceContractsTest.WcfClient.ClientDataClass, ServiceContractsTest.WcfClient"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
Server code (mine):
public class TestService : ITestService
{
public IDataContract TestSharedInterface(IDataContract clientData)
{
ServerDataClass convertedClientData = (ServerDataClass)clientData;
IDataContract serverData = new ServerDataClass() { MyProperty = convertedClientData.MyProperty + " + server data added" };
return serverData;
}
}
[DataContract(Name = "IDataContract", Namespace = "http://services.sliderhouserules.com")]
public class ServerDataClass : IDataContract
{
[DataMember]
public string MyProperty { get; set; }
}
Server config:
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="ServiceContractsTest.Contracts.DataContracts.IDataContract, ServiceContractsTest.Contracts">
<knownType type="ServiceContractsTest.WcfService.ServerDataClass, ServiceContractsTest.WcfService"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
I am getting a serialization error on the client call complaining about known types. Am I just missing some metadata markup in that client class? I'm at a loss as to where to even know the problem even lies, as I've tried all the searches I can think of and no one seems to have dealt with this specific scenario.
Basically, I want ClientDataClass to serialize to <IDataContract><MyProperty>client data</MyProperty></IDataContract> and then be able to deserialize that into a ServerDataClass instance. This seems like it should be possible.
If your data contracts are interfaces WCF can't know what object to instantiate for an incoming request. There is no need for the class to be the same as in the service, after all the Add Service Reference reads the WSDL and generates new classes based on the type info in the WSDL.
This blog gives me the right direction to find the solution for my problem. Actually I have exactly the same scenario like sliderhouserules describes in his post.
But in my scenario I can't use any abstract or base class to inherit from. So I used a TypesHelper class to read the dataContractSerializer section by myself and pass the relevant types to the WCF service.
namespace ExampleNamespace
{
public interface IJustAInstance { }
[ServiceContract]
[ServiceKnownType("GetKnownTypes", typeof(ExampleNamespace.TypesHelper))]
public interface ICreateInstance
{
IJustAInstance CreateInstance();
}
public static class TypesHelper
{
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
{
DataContractSerializerSection section = (DataContractSerializerSection)
ConfigurationManager.GetSection(
"system.runtime.serialization/dataContractSerializer");
if (dataContractSerializerSection != null)
{
foreach (DeclaredTypeElement item in dataContractSerializerSection.DeclaredTypes)
{
foreach (TypeElement innterItem in item.KnownTypes)
{
Type type = Type.GetType(innterItem.Type);
if (typeof(IJustAInstance).IsAssignableFrom(type ))
yield return type;
}
}
}
}
}
}
You could create a BaseContract that your ClientContract and ServerContract can provide (as property) and that you can use in the respective constructor when creating new instances of the ClientContract or ServerContract.
Then you only have to add the BaseContract to your shared lib.