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(...)
Related
I'm trying to create a service which manages different account providers and accounts within our application (WPF desktop app).
My idea was to have account providers, which would be external web services such as Jira, Gitlab, etc. Each provider has a list with accounts.
Depending on the provider it can have different means to authorize our software to use a users account. Our first implementation is using OAuth tokens for authorization and a Rest API to interact with a web service.
Obviously, we need some restrictions e.g. an OAuthProvider will only accept OAuthAccounts in its Accounts list.
The ideal case would be if we could store all providers no matter their accounts type in a single list of the form List<IAccountProvider<IAccount>> someList. However I couldn't get it to compile. The error is:
Error CS1503 Argument 1: cannot convert from 'TestProject.Program.JiraProvider' to 'TestProject.Program.IAccountProvider<TestProject.Program.IAccount>'
I tried to make IAccountProvider covariant but this in turn restricts me very much in using the interface...
Is there some way to get it to compile using this class hierarchy? If you have a better idea how to setup the hierarchy then I'd be glad to hear your suggestions :).
static int Main(string[] args)
{
var jiraProv = new JiraProvider();
//var someList = new List<IAccountProvider<OAuthAccount>>(); // this would work - but it's not what I want...
var someList = new List<IAccountProvider<IAccount>>(); // this doesn't seem to work
someList.Add(jiraProv); // error CS1503 cannot convert from X to Y
return 0;
}
//-----------------
// Interfaces - details left out for brevity...
// Providers
public interface IAccountProvider<T>
where T : IAccount
{
List<T> Accounts { get; }
T CurrentAccount { get; }
void Login(T account);
}
public interface IOAuthProvider<T> : IAccountProvider<T>
where T : IOAuthAccount
{ }
// Accounts
public interface IAccount { }
public interface IOAuthAccount : IAccount { }
//-----------------
// Implementations - details left out for brevity...
public class OAuthAccount : IOAuthAccount { }
public class JiraProvider : IOAuthProvider<OAuthAccount>
{
public List<OAuthAccount> Accounts { get; set; }
public OAuthAccount CurrentAccount { get; set; }
public void Login(OAuthAccount account) { }
}
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've been looking at many other questions on SO, many similar, but none seem to match the style of service reference, hence me asking. Most of them talk about using ChannelFactory, but this one uses ClientBase. I'm learning more about Unit testing & Moq. I want to test our repository class, which makes a call to a WCF Service.
I've tried mocking this many ways, including creating a constructor on the repo, taking the FISP interface.
How can I work this to be usable in the repo and also unit testable, mocking the WCF operation using moq?
The repository didn't pass in the interface (yet), as below. It's using the proxy client class.
public class FisPRepository : IFisPRepository
{
private readonly FISPClient _fisPClient;
public FisPRepository()
{
_fisPClient = new FISPClient
{
ClientCredentials =
{
UserName = {UserName = "xyz", Password = "cba"}
}
};
public person GetPersonFromId(string id)
{
return _fisPClient.getPerson(new personRequest()
{
reference = new referenceFilter { type = "FWI", value = id },
});
}
}
Generated reference
And here's the generated Reference code -
Interface:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://www.aUrl.com/fwi", ConfigurationName="FISP.FISP")]
public interface FISP {
[System.ServiceModel.OperationContractAttribute(Action="http://www.aUrl.com/fwi/FISP/getPersonRequest", ReplyAction="http://www.aUrl.com/fwi/FISP/getPersonResponse")]
[System.ServiceModel.FaultContractAttribute(typeof(FhSoap.FISP.FWiException), Action="http://www.aUrl.com/fwi/FISP/getPerson/Fault/FWiException", Name="FWiException")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(episodeTask))]
[return: System.ServiceModel.MessageParameterAttribute(Name="person")]
FhSoap.FISP.getPersonResponse getPerson(FhSoap.FISP.getPersonRequest request);
}
Client:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public interface FISPChannel : FhSoap.FISP.FISP, System.ServiceModel.IClientChannel {
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class FISPClient : System.ServiceModel.ClientBase<FhSoap.FISP.FISP>, FhSoap.FISP.FISP {
public FISPClient() {
}
public FISPClient(string endpointConfigurationName) :
base(endpointConfigurationName) {
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
FhSoap.FISP.getPersonResponse FhSoap.FISP.FISP.getPerson(FhSoap.FISP.getPersonRequest request) {
return base.Channel.getPerson(request);
}
public FhSoap.FISP.person getPerson(FhSoap.FISP.personRequest request) {
FhSoap.FISP.getPersonRequest inValue = new FhSoap.FISP.getPersonRequest();
inValue.request = request;
FhSoap.FISP.getPersonResponse retVal = ((FhSoap.FISP.FISP)(this)).getPerson(inValue);
return retVal.person;
}
}
Update
Following the suggestions in the comments below I tried using the interface to construct the client, is that what's meant? As that doesn't then create a client, it creates a channel.
public FisPRepository()
{
var factory = new ChannelFactory<FISPChannel>("BasicHttpBinding_SomthingService");
var credentialBehaviour = factory.Endpoint.Behaviors.Find<ClientCredentials>();
credentialBehaviour.UserName.UserName = "xyz";
credentialBehaviour.UserName.Password = "cba";
_fisPClient = factory.CreateChannel();
}
That _fisPClient = factory.CreateChannel(); is invalid, as it it creates a FISPChannel, not client. What am I missing?
your repository is working with your concrete client, you need to inject the client into the class onto an interface
response:
#Kritner, The FISPChannel? As opposed to the FISP interface?
Well, the normal convention is for interfaces to be "I" something like IFISP, but either way, the IFISP interface is what I would have used in the past (instead of the IFISPChannel. Though currently, if you attempted to use FISP, that interface would not have access to the ClientCredentials that you're currently setting in the class when newing up the client.
Ideally, you would not be setting your credentials on each repository, but in some sort of configuration. Once you've done that, you can refactor to something like this:
public class FisPRepository : IFisPRepository
{
private readonly FISP _fisp;
public FisPRepository(FISP fisp)
{
_fisp = fisp;
}
public person GetPersonFromId(string id)
{
return _fisP.getPerson(new personRequest()
{
reference = new referenceFilter { type = "FWI", value = id },
});
}
}
and of course, when constructing your repository, you'll need to pass in a concretion of the client - but for unit testing you'll be able to mock the FISP.
You can get a concretion of the client in several ways.
Use an IOC container like Ninject, Unity, AutoFac, etc
New up the concretion directly
Use service location
As syntax differs depending on your IOC or service location, so here's how you could get a repository now directly:
FisPRepository myRepo = new FisPRepository(new FISPClient());
injecting your concretion and coding to an abstraction is a design pattern known as dependency injection.
I'm adjusting my web application layers in a way to make the code more testable.
Currently the UI talks to a service locator passing in an interface, this returns the appropriate object based on that type:
ServiceLocator.Get<ISomeService>().ListStuff(arg1, arg2);
Internally, services are instantiated with an instance of IServiceContext and cached.
private static Lazy<IDictionary<Type, object>> _services = new Lazy<IDictionary<Type, object>>(GetServices);
public interface IServiceContext
{
IConfiguration Configuration { get; }
IUser CurrentUser { get; internal set; }
ILogProvider Log { get; }
ICacheProvider Cache { get; }
IProfilerProvider Profiler { get; }
}
public LogService(IServiceContext serviceContext)
: base(serviceContext) { }
I'm happy with the concept and it appears to be rugged enough, my only issue is I want to make the current logged in user available in the ServiceContext but unsure the best way to achieve it.
My thoughts travel along these potential options:
Keep a simple method in the ServiceLocator that handles getting the users session and injects it into the services as requests for them come in.
Move getting the current user out of the IServiceContext and into the ServiceBase base class of each service.
Stop doing this and make each service that needs a user dependent on it.
I appreciate any suggestions, I understand this question my not be in the true spirit of the site.
I have managed 4 days of trial and error to get to this point, just need the last piece of this puzzle.
There's probably many solutions, and I'm not fully sure I understand your question but I'll try to help anyway.
Whenever I need the current user I make a call to static utility class right in the context of the code that uses it. This way I eliminate the possibility of stale information.
You could make a class that implements IUser like
class User : IUser {
private System.Security.Principal.WindowsIdentity identity;
public User() {
this.identity = identity = System.Security.Principal.WindowsIdentity.GetCurrent();
}
public string UserName { get { return this.identity.Name; } }
}
And then maybe:
public class ServiceContext : IServiceContext
{
IUser CurrentUser { get { return new User(); } }
}
I am building a class library that interacts with various 3rd party API's. I have used an facade pattern to provide simplified access to complicated and confusing calls, and a factory pattern to return the correct implementation. I am now trying to build one of the implementation but cant think of an elegant design.
The implementation i am building requires a URL to be constructed (which i am doing via URIBuilder). I then need to "execute" the url. I then deserialize the Xml result into a class.
I am planning on using HttpClient to call the api with the URI i built, but am not sure on how to structure the class. The options i have thought of are:
A base class of my implementation so can call it via base.InvokeURI(Uri myUri).
A seperation class so it can be used by multiple implementations
I am also unsure where the deserialization should reside.
I think using Interface in this case is more suitable:
public interface IURLInvoke
{
string InvokeURI(Uri myUri);
}
// some implementation
public class YourURLInvoker: IURLInvoke
{
public string InvokeURI(Uri myUri)
{
// do something
}
}
public class YourClass
{
public IURLInvoke Invoker {get; set;}
public void InvokeURI(Uri myUri)
{
if(Invoker == null)
return;
string xml = Invoker.InvokeURI(Uri myUri);
// put your code for deserialization here
}
}
// here is an usage example:
YourClass a = new YourClass();
// set an Invoker, choose a strategy to invoke url
a.Invoker = new YourURLInvoker();
a.InvokeURI(url);
This approach is also called Strategy Pattern
Pls see dummy code using adapter pattern and dependency injection.
Idea is to create a interface and pass it around
public class Adapter{
public void processRequest(){
RequestProcessor processor = new RequestProcessor();
processor.processRequest();
}
}
public class RequestProcessor{
public void procesRequest(){
Irequest request = new HTTPRequest();
HTTPService service = new HTTPService();
// fetch the uri from builder class
URI url = URIBUIlder();
string response = service.sendRequest(request,url);
// now fetch type from just
Type t = Serializer.searialize<T>(response);
}
}
public Class Serializer{
public static T searialize<T>(string xml){
}
}
public interface IRequest{
public string sendRequest(uri url);
}
public class HTTPRequest:IRequest{
public string sendRequest(uri url){
// instantiate actual http request here and return response
}
}
//This will act as controller
public class HTTPService{
public string sendRequest(IRequest request,uri url) {
return request.sendRequest(url);
}
}