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.
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);
}
}
The API Call
I am making a REST API call with the following message body:
{"Method":{"Token":"0","Value":"0"}}
400 Response
I am getting a 400 Bad Request response from the api with the following body:
{"Message":"The request is invalid.","ModelState":{"request.Method.Token":["Could not create an instance of type Namespace.ActionMethod. Type is an interface or abstract class and cannot be instantiated. Path 'ActionMethod.Token'."]}}
Code Information
The method which is receiving the api call looks like this:
public MethodResponse MakeMethodCall([Required] [FromBody] MethodRequest request)
MethodRequest has a Method property which is an abstract type.
public class MethodRequest
{
public ActionMethod Method { get; set; }
}
public abstract class ActionMethod
{
public string Token { get; set; }
}
public class FirstMethod : ActionMethod
{
public string Value { get; set; }
}
Question
How can I call the REST API and have it recognize that the type of Method is FirstMethod, instead of it trying to instantiate the abstract type ActionMethod?
Note that I will need to have more implementations of ActionMethod in the future (ie. SecondMethod), so the solution will need to include an extensible ActionMethod (interface would also be fine).
EDIT
It would also be reasonable to include an enum to identify which implementation of ActionMethod was being targeted by the API call.
I'm currently using a solution which has an ActionMethodType enum and both FirstMethod and SecondMethod fields. I'm checking these fields based on the value of ActionMethodType. This works, but I would like to have a single [Required] field into which I could pass any implementation of ActionMethod.
Can't be done. How would the framework know to instantiate FirstMethod for this parameter? What if you had another subclass of ActionMethod that also had a Value property? Now it's even more ambiguous for the framework to figure out on it's own. You could do a bunch of work, creating a custom formatter (http://blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx) but ultimately it would be easier to just have a single class that includes all possible properties a client could send OR have separate API endpoints for the client to call using different concrete types as the parameter.
If I understand you correctly, you could implement this with a custom model binder and a factory pattern.
public class MethodRequestBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
HttpRequestBase request = controllerContext.HttpContext.Request;
//use the request object to make a call to your factory for the
//appropriate ActionMethod subtype you want to create, or however
//else you see fit.
var curActionMethod = MyFactory.Get(request.QueryString);
var boundObj = new MethodRequest()
{
Method = curActionMethod
}
return boundObj;
}
}
register your model binder in app_start:
ModelBinders.Binders.Add(typeof(MethodRequest), new MethodRequestBinder());
now, just decorate your controller action method:
public ActionResult Index([ModelBinder(typeof(MethodRequestBinder))] MethodRequest request)
{
//etc..
}
I used this as a starting point: http://www.codeproject.com/Articles/605595/ASP-NET-MVC-Custom-Model-Binder
Remove the abstract keyword from your ActionMethod, or mark the Token property abstract and override it in the inherited classes:
public abstract class ActionMethod
{
public abstract string Token { get; set; }
}
public class FirstMethod : ActionMethod
{
public string Value { get; set; }
public override string Token
{
get;
set;
}
}
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
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.