In c# .Net Framework 4.5 (Visual Studio Ultimate 2012, Version 11.0.61219.00 Update 5), I'm trying to define a service variable at runtime for which webservice to use. Each webservice (there are many) are all defined the same except for the endpoint url but the credentials will not cross over to authenticate. The below condition is menial to simplify the issue at hand. The following code gives the error: Cannot implicitly convert type WebService2.Service to WebService1.Service.
What I've tried: calling functions to return the proper service but the parameters or assignment all require a specific type.
var service = new WebService1.Service();
service = new WebService2.Service();
I want to be able to use the variable service in the rest of the program without having to duplicate code everywhere for using the many web service references.
It seems like what you are looking to do, you would need a common interface between the two services so you could inject whichever service you wish to use.
public class WebService1 : IWebService {...service code}
public class WebService2 : IWebService{...service code}
public interface IWebService{...service methods you will be calling}
Then you could do the following.
IWebService service = new WebService1.Service();
service = new WebService2.Service();
Assuming that the different services share the same method names, you can create an interface that all of the services implement by using the interface
IMyService.cs
interface IMyService
{
void MyMethod(string filter);
}
MyWebServiceImplementation.cs
public class MyWebServiceImplementation : IMyService
{
public void MyMethod(string filter);
}
MySecondWebServiceImplementation.cs
public class MySecondWebServiceImplementation : IMyService
{
public void MyMethod(string filter);
}
MyImplemetationCode.cs
//Use different services from same variable
IMyService service = new MyWebServiceImplementation();
service.MyMethod("filter");
service = new MySecondWebServiceImplementation();
service.MyMethod("another filter");
Related
I'm updating a few web services that have some components in common, so I thought that by creating a library that has that code in it, it could ease maintenance. When using a class from said library, the web service forces me to call the method with its proxy class.
Since the system is somewhat old, I can't change the architecture. The compilation is made in x64. I've already attempted to change the "Reuse types in referenced assemblies".
Referencing a class "x" from the "y" library on a web service "w" forces me to use the class "w.x" instead of "y.x" on a service method call.
Best regards,
Fábio Jesus
The code that I can provide is the following:
Library
namespace Library1
{
public class Class1
{
}
}
Service
namespace Services
{
[ServiceContract]
public interface Service
{
[OperationContract]
void Method(Library1.Class1 cc);
}
}
Client
namespace Client
{
public class ClientControl : PageControl
{
public void Execute(){
using(var _service = new Services.Service){
var cc = new Library1.Class1();
_service.Method(cc);
}
}
}
}
This question already has answers here:
How do I pass values to the constructor on my wcf service?
(9 answers)
Closed 7 years ago.
I'm building server in C# and WCF. I have my Service and Contract with methods used by Client app. But the whole logic is separated in different class: BusinessLogic. I will inject all I need in BussinessLogic, like repositories/database providers or other data stored in memory. I use Poor man's dependency to build my BussinessLogic (it's my composition root). It's a console application, so BussinessLogic is creaed/resolved in Main(string[] args) method.
My problem is that WCF services are created with parameterless constructor, independent of the rest of the server. They are created every time, when used be the Client.
This is how my server looks like:
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(ServiceLayer), new Uri("net.tcp://localhost:8005"));
host.Open();
Console.WriteLine("Running... Press key to stop");
Console.ReadKey();
}
My services:
[ServiceContract]
public interface IServiceContract
{
[OperationContract]
...
}
public class ServiceLayer : IServiceContract
{
IBusinessLogic _businessLogic;
public ServiceLayer(IBusinessLogic businessLogic)
{
_businessLogic = businessLogic;
}
// Here, I would like to use IBusinessLogic
...
}
I found how to do this using IoC here (I didn't test it tho), but I'm looking for a best solution with Poor man's dependency, without any container or tool, just C# and .NET. If there isn't any solution as good as IoC or close to it, please comment.
If you model your application around commands and queries, it becomes very easy to create your WCF service as a thin maintenance free layer with just one service class.
When you have just one service class, you can use this service class itself as Composition Root or Humble Object and this means you don't need to inject any dependencies into the service class. This prevents you from having to do any integration into the WCF pipeline when it comes to dependency injection, at all!
When you apply these patterns, you can reduce your service to the following code:
[ServiceKnownType(nameof(GetKnownTypes)]
public class CommandService
{
[OperationContract, FaultContract(typeof(ValidationError))]
public void Execute(dynamic command) {
CreateCommandHandler(command.GetType()).Handle(command);
}
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider cap) {
yield return typeof(ShipOrder);
yield return typeof(CancelOrder);
yield return typeof(ConfirmOrder);
}
// Singletons
private static IUserContext userContext = new WcfUserContext();
private static dynamic CreateCommandHandler(Type commandType)
{
var context = new DbContext();
if (commandType == typeof(ShipOrder))
return Decorate(new ShipOrderHandler(context));
if (commandType == typeof(CancelOrder))
return Decorate(new CancelOrderHandler(context));
if (commandType == typeof(ConfirmOrder))
return Decorate(new ConfirmOrderHandler(context, userContext));
throw new ArgumentException("Unknown: " + commandType.FullName);
}
private static ICommandHandler<T> Decorate<T>(ICommandHandler<T> handler) {
return new WcfExceptionTranslatorCommandHandlerDecorator(
new LoggingCommandHandlerDecorator(
new Logger(),
new AuditTrailingCommandHandlerDecorator(
new PermissionCheckerCommandHandlerDecorator(
new ValidationCommandHandlerDecorator(
new TransactionCommandHandlerDecorator(
handler))))));
}
}
Poor man's DI is now called Pure DI.
You can use Pure DI to compose WCF applications. You need to do that in the Composition Root.
In WCF application, the Composition Root is a custom ServiceHostFactory.
This answer shows an example of how to do that.
You can customize the code in that answer to add more dependencies.
I am updating a web service from VB to C#. This is a WCF service.
The web service implements 2 interfaces.
When I add the web service to a test application, only one of the interfaces is accessible.
When I try to invoke a method from the second interface, the method signature is not recognized.
This works in VB and I am hoping I can do the same in C#.
This is the implementation of the web service class:
PayService Interface:
namespace PayService
{
[ServiceContract (Namespace...)]
public interface IPayService
{
//Initiate a credit card authorization.
[OperationContract(IsOneWay = true)]
void Authorize(...12 arguments here...);
}
PayService2 Interface:
namespace PayService2
{
[ServiceContract (Namespace...)]
public interface IPayService
{
//Initiate a credit card authorization.
[OperationContract(IsOneWay = true)]
void Authorize(...13 arguments here...);
}
public partial class PayService : IPayService, IPayService2
{
Authorize(...there are 12 arguments here)
Authorize(...there are 13 arguments here)
...more methods but they are not a problem.
}
The calling application is just a web application to test the web service.
//Create instance of PayService
PayService.PayServiceClient payService = new PayService.PayServiceClient();
payService.Authorize(...12 arguments) //this one works fine
payService.Authorize(...13 arguments) //this one is not recognized
Does anyone have an idea why not all of the methods would be visible in the web application that uses the PayService?
Thanks.
Check this out: https://stackoverflow.com/a/720389/487940
You basically want to combine the 2 interfaces into a single interface, like this:
public interface IMyInterface : IInterface1, IInterface2
How can I configure an Autofac container so it resolves the dependencies of a WCF service based on properties values of the operation-parameter (request object)?
For example, given this data contract...
[DataContract]
public class MyRequest
{
[DataMember]
public bool MyBool { get; set; }
}
this WCF service...
public class MyWcfService : IWcfService
{
private IService m_service;
public MyWcfService(IService service)
{
m_service = service;
}
public virtual MyResponse Operation(MyRequest request) { }
}
and these dependencies...
public interface IService { }
public class TypeA : IService { }
public class TypeB : IService { }
I would like the container to resolve TypeA if MyBool equals true and TypeB otherwise. Is that feature available? Should I approach the problem differently?
Constraints:
Avoiding the Autofac.Extras.Multitenant package is a plus.
Keeping the signature of the service constructor unchanged is also desired. (See my answer below)
There are a few ways to achieve this. One of the ways is to use IIndex<K,V>. It's built-in "lookup" feature that chooses between service implementations based on a key. You can find more info on Autofac's wiki page. An example code could look like:
// Register your dependency with a key, for example a bool flag
builder.RegisterType<TypeA>().Keyed<IService>(true);
builder.RegisterType<TypeB>().Keyed<IService>(false);
// Your service could look like:
public class MyWcfService
{
private readonly IIndex<bool, IService> _services;
// Inject IIndex<Key,Value> into the constructor, Autofac will handle it automatically
public MyWcfService(IIndex<bool, IService> services)
{
_services = services;
}
public virtual void Operation(MyRequest request)
{
// Get the service that you need by the key
var service = _services[request.MyBool];
}
}
Another approach is to use Metadata feature. More information on wiki page.
Option 1 - Using Autofac:
The Autofac instance provider that creates your service instance does not use or pass along the operation's message. Here's the latest implementation of the method in Autofac. Notice the message parameter is unused.
public class AutofacInstanceProvider : IInstanceProvider
{
// lots of code removed...
public object GetInstance(InstanceContext instanceContext, Message message)
{
if (instanceContext == null)
{
throw new ArgumentNullException("instanceContext");
}
var extension = new AutofacInstanceContext(_rootLifetimeScope);
instanceContext.Extensions.Add(extension);
return extension.Resolve(_serviceData);
}
}
So to get the behavior you want with existing Autofac code, you'll need to inject the dependency into your class using something other than constructor injection, which is #Alexandr Nikitin's solution. This is reasonable, but I agree with the comment "not loving it".
Option 2 - A Custom IInstanceProvider:
Writing a custom WCF IInstanceProvider is a reasonable option, but it will be a lot of code.
The good news is that the code in Autoface.Integration.WCF is a nice example and you could plug your implementation into Autofac.
The bad news is that Autofac.Integration.WCF code doesn't itself use dependency injection. For example AutofacDependencyInjectionServiceBehavior directly calls var instanceProvider = new AutofacInstanceProvider(_rootLifetimeScope, _serviceData). As a result you'll you have to implement a replacement for AutofacInstanceProvider, AutofacDependencyInjectionServiceBehavior, AutofacHostFactory, and probably more. Then you'll need to create an extension for the AutofacInstanceContext to contain the information read from the message. Its a lot of code.
If you are going to do the custom IInstanceProvider I suggest reading up on Carlos Figueira's blog:
WCF Extensibility – IInstanceProvider - for good background
WCF Extensibility – Message Inspectors - Search for the section that starts with WCF Message objects can only be “consumed once". You'll need to follow these rules when inspecting the message.
I have a class Server that implements interface IServer that is accessible using .net remoting (i have no chioce on the matter JICYAW).
internally this server uses other classes to implement logic and data access.
this server class has constructor injected dependencies that it needs to do its job.
when a client calls in (per call) the remoting framework will instatiate a Server instance using a parameterless constructor and not (of course) using Ninject.
how can i get Ninject to be the one in charge for new'ing up the class ?
i have seen this similar SO question but this isnt relevant for Ninject.
thanks for your help
You can create a service facade that will be called by the client. This facade will internally call your container to resolve the real service. For instance:
public class ServiceFacade : IService
{
private readonly IService service;
// default constructor
public ServiceFacade()
{
this.service = YourContainer.Current.Resolve<IService>();
}
void IService.ServiceOperation()
{
this.service.ServiceOperation();
}
}
What might work is to intercept the calls to those objects using a proxy and forward the calls to the real object. Note that I'm not very experienced with this, so I'm not sure if this actually works, but here goes:
public class DependencyInjectionProxy : RealProxy
{
private object realInstance;
public DependencyInjectionProxy(Type classToProxy,
object realInstance) : base(classToProxy)
{
this.realInstance = realInstance;
}
public static T MakeProxy<T>(T realInstance)
{
return (T)(new DependencyInjectionProxy(typeof(T),
realInstance).GetTransparentProxy());
}
public override IMessage Invoke(IMessage msg)
{
if (msg is IMethodCallMessage)
{
var message = (IMethodCallMessage)msg;
object value = message.MethodBase.Invoke(
this.realInstance, message.Args);
Console.WriteLine(value);
return new ReturnMessage(value, null, 0, null, message);
}
return msg;
}
}
This works when you do something like this:
var container = new YourContainer();
container.RegisterSingle<IService, Service>();
IService proxy = DependencyInjectionProxy.MakeProxy<IService>(
container.Resolve<IService>());
proxy.SomeMethod();
This works great, but to be honest, I have no idea how to configure this in a way that you can intercept incoming calls this way. Somewhere you need to register your DependencyInjectionProxy, but that's where my experience with remoting stops :-)