Inject parameter at WCF service constructor using NInject - c#

I've seen several examples on Internet setting up an NInject Factory modifying svc file. I don't have this svc file (or I don't know where's it).
I've a slight WCF service:
IService interface:
[ServiceContract]
public interface IFileSystemPluginService
{
[OperationContract]
void saveConfiguration(Configuration.Configuration configuration, string userId);
[OperationContract]
Configuration.Configuration getConfiguration(string userId);
}
IService implementation:
public class Service : IService
{
private IUserConfigurable userConfigurablePlugin;
public Service(IUserConfigurable configurablePlugin)
{
this.configurablePlugin = configurablePlugin;
}
}
In order to kick the service off I'm setting configuration up in code:
private void initializeWCFService()
{
string baseAdress = "xxx";
Uri baseAddressUri = new Uri(baseAdress);
this.serviceHost = new System.ServiceModel.ServiceHost(typeof(Service), baseAddressUri);
this.serviceHost.AddServiceEndpoint(
typeof(IService),
new System.ServiceModel.WSHttpBinding(),
string.Empty
);
System.ServiceModel.Description.ServiceMetadataBehavior smb = new System.ServiceModel.Description.ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri(baseAdress);
this.serviceHost.Description.Behaviors.Add(smb);
this.serviceHost.Open();
}
I need to inject a IUserConfigurable object in Service constructor.

Related

Service Fabric service with WCF communication deployment

Here is a simple Service Fabric stateless service with WCF communication and it's client - a console app. It works well on the local cluster, client gets responce from the service. But I don't know how to communicate with a service if I deploy it in the cloud. What should I do to access it from console app?
SF Stateless service with WCF communications:
Contract:
[ServiceContract]
public interface IPresidentialService
{
[OperationContract]
Task<string> GetInfo();
}
Service:
internal sealed class PresidentialService : StatelessService, IPresidentialService
{
public PresidentialService(StatelessServiceContext context) : base(context)
{
}
public Task<string> GetInfo() => Task.FromResult($"Node {Context.NodeContext.NodeName} operating");
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[]
{
new ServiceInstanceListener(context =>
new WcfCommunicationListener<IPresidentialService>(wcfServiceObject: this, serviceContext: context,
endpointResourceName: "WcfServiceEndpoint",
listenerBinding: WcfUtility.CreateTcpListenerBinding()))
};
}
}
}
Client console app:
WCF client:
public class PresidentialServiceClient : ServicePartitionClient<WcfCommunicationClient<IPresidentialService>>
{
public PresidentialServiceClient(
ICommunicationClientFactory<WcfCommunicationClient<IPresidentialService>> communicationClientFactory,
Uri serviceUri, ServicePartitionKey partitionKey = null,
TargetReplicaSelector targetReplicaSelector = TargetReplicaSelector.Default, string listenerName = null,
OperationRetrySettings retrySettings = null) : base(communicationClientFactory, serviceUri, partitionKey,
targetReplicaSelector, listenerName, retrySettings)
{
}
public Task<string> GetInfo() => InvokeWithRetryAsync(client => client.Channel.GetInfo());
}
Client App:
private static void Main(string[] args)
{
var binding = WcfUtility.CreateTcpClientBinding();
var partitionResolver = ServicePartitionResolver.GetDefault();
var wcfClientFactory =
new WcfCommunicationClientFactory<IPresidentialService>(binding,
servicePartitionResolver: partitionResolver);
var serviceUri = new Uri("fabric:/Application5/PresidentialService");
var client = new PresidentialServiceClient(wcfClientFactory, serviceUri, ServicePartitionKey.Singleton);
do
{
Console.WriteLine(client.GetInfo().Result);
Console.ReadKey();
} while (true);
}
Added to ServiceManifest.xml:
<Endpoints>
<Endpoint Name="WcfServiceEndpoint" />
</Endpoints>
UPDATE
Changed ServicePartitionResolver:
var partitionResolver = new ServicePartitionResolver("sfapp.westeurope.cloudapp.azure.com:19000");
Still not works.
UPDATE
Added a load balancer rule for TCP port 777.
When the service is running in the cloud, you can't use the default resolver.
The default ServicePartitionResolver assumes that the client is
running in same cluster as the service. If that is not the case,
create a ServicePartitionResolver object and pass in the cluster
connection endpoints.
Try something like
ServicePartitionResolver resolver = new ServicePartitionResolver("mycluster.cloudapp.azure.com:19000");
https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-wcf

Cannot access a disposed object when calling callback method

I've a Duplex TCP IP WCF service. I'm currently unit-testing it.
In everyone of my test, I setup a new server, create a new ChannelFactory, create the InstanceContext and do the call.
Then I trigger the event(it's a Mock on the server side), and the server give me this exception when it tries to reach the client:
Exception thrown: 'System.ObjectDisposedException' in mscorlib.dll
Additional information: Cannot access a disposed object.
Important point, this happens ONLY when I run all the tests in a row(sequentially executed but in the same execution).
There is nothing special about my service:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IMyServiceCallback))]
public interface IMyService{
[OperationContract]
void SomeVariousMethods();
}
[ServiceContract]
public interface IMyServiceCallback
{
[OperationContract]
void HandleMessageFromServer(String message);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService{
public MyService(ISomeServerComponent component){
component.OnMessage += OnMessageReceived;
}
public void SomeVariousMethods(){
//...
}
private void OnMessageReceived(object sender, EventArgs<String> e){
IMyServiceCallback callback = OperationContext.Current.GetCallbackChannel<IMyServiceCallback>();
callBack.HandleMessageFromServer(e.Data);//Crash here
}
}
And here is how I'm currently UnitTesting it(not exactly, I've a lot of this that has been extracted in some helpers:
[TestFixture]
public class MyServiceTest:IMyServiceCallback{
private Mock<ISomeServerComponent> _mock;
[OneTimeSetUp]
public void Setup(){
//... Creating a mock for the ISomeServerComponent that the MyService receives
}
[Test]
public void TestSomeVariousMethods(){
string serviceName = nameof(TestSomeVariousMethods);
using(ServiceHost host = CreateServer(_mock.Object,serviceName)){
using (IMyService service = CreateClient(serviceName, this)){
service.SomeVariousMethods();
}
}
}
[Test]
public void TestCallback(){
string serviceName = nameof(TestSomeVariousMethods);
using(ServiceHost host = CreateServer(_mock.Object,serviceName)){
using (IMyService service = CreateClient(serviceName, this)){
_mock.TriggerCallBack();
//Assert-that-the-flag-has-been-set
}
}
}
public void HandleMessageFromServer(String msg){
//Flag that this method has been called
}
private ServiceHost CreateServer(ISomeServerComponent mock, string serviceName){
UnityServiceHost serviceHost = new UnityServiceHost(m_container);//This extends ServiceHost to be able to inject some objects to my services
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
binding.ReliableSession.Enabled = true;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
binding.MaxBufferPoolSize = Int64.MaxValue;
binding.MaxBufferSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
Uri uri = new Uri(String.Format("net.tcp://{0}:{1}/{2}", IPAddress.Any, 9999, serviceName));
ServiceEndpoint serviceEndpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(IMyService)), binding, uri);
serviceEndpoint.EndpointBehaviors.Add(new ProtoEndpointBehavior());
serviceHost.AddServiceEndpoint(serviceEndpoint);
return serviceHost;
}
private IMyService CreateClient(string serviceName, IMyServiceCallback callback){
UnityServiceHost serviceHost = new UnityServiceHost(m_container);//This extends ServiceHost to be able to inject some objects to my services
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
binding.ReliableSession.Enabled = true;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
binding.MaxBufferPoolSize = Int64.MaxValue;
binding.MaxBufferSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
Uri uri = new Uri(String.Format("net.tcp://{0}:{1}/{2}", IPAddress.Loopback, 9999, serviceName));
InstanceContext context = new InstanceContext(callBack);
DuplexChannelFactory channelFactory = new DuplexChannelFactory<T>(context, binding, new EndpointAddress(uri));
return channelFactory.CreateChannel()
}
}
Funny part is that all of this works when I'm ONLY running TestCallback test, but if I run all the test of the class, it fails, like if the second time, the InstanceContext was not creating properly the callback.
Any idea how to avoid this?
I finally found the issue. I feel a little bit stupid, but in fact, in the Service implementation, I was not unregistering from the OnMessage correctly, so when the event was triggered, the previous service instance were trying to communicate with the already closed client.

WCF Azure Hosted Client using Service Bus and Castle Windsor in console app

Hi I'm trying to get dependency injection to work using Castle Windsor in a console app to host WCF service in Azure using the example in:
https://azure.microsoft.com/en-gb/documentation/articles/service-bus-dotnet-how-to-use-relay/
My WCF service works fine using Castle Windsor (Small sample):
public class PersonService : IPersonService
{
private readonly IPersonManager _personManager;
public PersonService(IPersonManager personManager)
{
_personManager = personManager;
}
public Message Create(Person person)
{
Message result = _ personManager.Create(person);
}
}
Castle Windsor (in wcf service Global.asax)
private void BuildWindsorContainer ()
{
var container = new WindsorContainer();
container.Kernel.AddFacility<WcfFacility>();
container.Kernel.Register(
Component.For< IPersonManager >().ImplementedBy<PersonManager >(),
Component.For<IPersonService>()
.ImplementedBy<PersonService>()
.Named("WebS.PersonService"),
);
}
In My hosted Client which calls the WCF service I have:
private static ServiceHost CallPersonService()
{
BuildWindsorContainer ();
var sh = new ServiceHost(typeof (PersonService));
sh.AddServiceEndpoint(typeof (IPersonService), new NetTcpBinding(), "net.tcp://localhost:37050/person");
sh.AddServiceEndpoint(typeof (IPersonService), new NetTcpRelayBinding(),
ServiceBusEnvironment.CreateServiceUri("sb", ServiceNamespace, "person"))
.Behaviors.Add(new TransportClientEndpointBehavior
{
TokenProvider =
TokenProvider.CreateSharedAccessSignatureTokenProvider("RootManageSharedAccessKey", Key)
});
private void BuildWindsorContainer ()
{
var container = new WindsorContainer();
container.Kernel.AddFacility<WcfFacility>();
container.Kernel.Register(
Component.For< IPersonManager >().ImplementedBy<PersonManager >(),
Component.For<IPersonService>()
.ImplementedBy<PersonService>()
.Named("WebS.PersonService"),
);
}
How do I get the dependencies to be injected into service from the client?
var sh = new ServiceHost(typeof (PersonService));
sh.AddServiceEndpoint(typeof (IPersonService), new NetTcpBinding(), "net.tcp://localhost:37050/person");
IPersonManager is null in service when the client runs.
Try
var sh = (ServiceHost)new DefaultServiceHostFactory()
.CreateServiceHost(typeof(PersonService).AssemblyQualifiedName, new Uri[] { });

Host multiple contracts in one WCF service [duplicate]

This question already has answers here:
Run WCF ServiceHost with multiple contracts
(8 answers)
Closed 9 years ago.
Is it possible to host multiple service contracts in one WCF service? If so, how? I've been googling and some posts say you can do it (but not how) and others have said it's just not possible.
When I run the server, I get this error:
The contract name 'ConsoleAppWcfCommon.IBarService' could not be found
in the list of contracts implemented by the service
'ConsoleAppWcfServer.FooService'.
This is my server code:
static void Main(string[] args)
{
string serviceAddress = "net.tcp://localhost:8088/FooBarService";
// I'm stuck here as I have to pick *one* service
ServiceHost selfServiceHost = new ServiceHost(typeof(FooService));
// I can add both endpoints here, but this is what gives me the error.
selfServiceHost.AddServiceEndpoint(typeof(IFooService), new NetTcpBinding(), serviceAddress);
selfServiceHost.AddServiceEndpoint(typeof(IBarService), new NetTcpBinding(), serviceAddress);
selfServiceHost.Open();
Console.ReadLine();
selfServiceHost.Close();
}
And this is the client code:
static void Main(string[] args)
{
NetTcpBinding netTcpBinding = new NetTcpBinding();
EndpointAddress endpointAddress = new EndpointAddress("net.tcp://localhost:8088/FooBarService");
// Call IFooService
var channelFactoryFoo = new ChannelFactory<IFooService>(netTcpBinding, endpointAddress);
IFooService channelFoo = channelFactoryFoo.CreateChannel();
Debug.WriteLine(channelFoo.FooMethod1());
// Call IBarService
var channelFactoryBar = new ChannelFactory<IBarService>(netTcpBinding, endpointAddress);
IBarService channelBar = channelFactoryBar.CreateChannel();
Debug.WriteLine(channelBar.BarMethod1());
}
My goal is to let the client make a call to Foo (or Bar) and only see the methods available to each. In my real application, I have about 10 domain entities with about four operations on each. I'm trying not to have one interface with 40 methods in it. And I don't want to have to host 10 different WCF services to do this.
As marc_s pointed out, the answer was to have one service implementation class that implements both interfaces. Below is the full working code.
Server:
static void Main(string[] args)
{
string serviceAddress = "net.tcp://localhost:8088/FooBarService";
ServiceHost selfServiceHost = new ServiceHost(typeof(FooService));
// The endpoints need to share this binding.
var binding = new NetTcpBinding();
selfServiceHost.AddServiceEndpoint(typeof(IFooService), binding, serviceAddress);
selfServiceHost.AddServiceEndpoint(typeof(IBarService), binding, serviceAddress);
selfServiceHost.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press any key to terminate service.");
Console.WriteLine();
Console.ReadKey();
selfServiceHost.Close();
}
Client:
static void Main(string[] args)
{
NetTcpBinding netTcpBinding = new NetTcpBinding();
EndpointAddress endpointAddress = new EndpointAddress("net.tcp://localhost:8088/FooBarService");
// Call IFooService
var channelFactoryFoo = new ChannelFactory<IFooService>(netTcpBinding, endpointAddress);
IFooService channelFoo = channelFactoryFoo.CreateChannel();
Console.WriteLine(channelFoo.FooMethod1());
// Call IBarService
var channelFactoryBar = new ChannelFactory<IBarService>(netTcpBinding, endpointAddress);
IBarService channelBar = channelFactoryBar.CreateChannel();
Console.WriteLine(channelBar.BarMethod1());
Console.ReadKey();
}
Foo Contract:
[ServiceContract]
public interface IFooService
{
[OperationContract]
string FooMethod1();
[OperationContract]
string FooMethod2();
}
Bar Contract:
[ServiceContract]
public interface IBarService
{
[OperationContract]
string BarMethod1();
[OperationContract]
string BarMethod2();
}
Foo Service:
public class FooService : IFooService, IBarService
{
public string FooMethod1()
{
return "FooMethod1";
}
public string FooMethod2()
{
return "FooMethod2";
}
public string BarMethod1()
{
return "BarMethod1";
}
public string BarMethod2()
{
return "BarMethod2";
}
}

Using PerWcfSession lifestyle with Castle WCF Integration Facility

The following code uses the Castle Windsor 3.0's WCF Integration Facility to register a WCF self-hosted service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using Castle.Facilities.WcfIntegration;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace SelfHost
{
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
string SayHello(string name);
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class HelloWorldService : IHelloWorldService
{
private readonly PerSession _perSession;
public HelloWorldService(PerSession perSession)
{
_perSession = perSession;
}
public string SayHello(string name)
{
return string.Format("Hello, {0} {1}", name, _perSession.Info());
}
}
public class PerSession
{
private readonly string _now;
public PerSession()
{
_now = DateTime.Now.ToString();
}
public string Info()
{
return _now;
}
}
internal class Program
{
private static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8080/hello");
var container = new WindsorContainer();
container.AddFacility<WcfFacility>();
container.Register(
Component.For<PerSession>().LifeStyle.PerWcfSession(),
Component.For<IHelloWorldService>()
.ImplementedBy<HelloWorldService>()
.AsWcfService(
new DefaultServiceModel()
.AddBaseAddresses(baseAddress)
.AddEndpoints(WcfEndpoint.BoundTo(new BasicHttpBinding()).At("basic"))
.PublishMetadata(o => o.EnableHttpGet())
)
);
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
}
}
}
Trying to invoke the SayHello method using WcfTestClient.exe results in the following error:
Could not obtain scope for component SelfHost.PerSession. This is most
likely either a bug in custom IScopeAccessor or you're trying to
access scoped component outside of the scope (like a per-web-request
component outside of web request etc)
What is the correct way to use PerWcfSession components?
So I was missing a few things:
The ServiceContract needs to set the SessionMode property
[ServiceContract(SessionMode = SessionMode.Required)]
Likewise the ServiceBehavior needs to set the InstanceContextMode
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerSession)]
Finally, the service registration needs to change the Lifestyle from the default (Singleton) so that it gets recreated for each request (and the dependencies are re-evaluated) - Transient or PerWcfSession would work.
Also, because we require a session, the binding needs to change from the basicHttpBinding to something that that supports sessions:
Component.For<IHelloWorldService>()
.ImplementedBy<HelloWorldService>()
.LifestyleTransient()
.AsWcfService(
new DefaultServiceModel()
.AddBaseAddresses(baseAddress)
.AddEndpoints(WcfEndpoint.BoundTo(new WSHttpBinding()).At("myBinding"))
.PublishMetadata(o => o.EnableHttpGet())
)
Which makes the final code look like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using Castle.Facilities.WcfIntegration;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace SelfHost
{
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IHelloWorldService
{
[OperationContract]
string SayHello(string name);
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerSession)]
public class HelloWorldService : IHelloWorldService
{
private readonly PerSession _perSession;
public HelloWorldService(PerSession perSession)
{
_perSession = perSession;
}
public string SayHello(string name)
{
return string.Format("Hello, {0} {1}", name, _perSession.Info());
}
}
public class PerSession
{
private readonly string _now;
public PerSession()
{
_now = DateTime.Now.ToString();
}
public string Info()
{
return _now;
}
}
internal class Program
{
private static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8080/hello");
var container = new WindsorContainer();
container.AddFacility<WcfFacility>();
container.Register(
Component.For<PerSession>().LifeStyle.PerWebRequest,
Component.For<IHelloWorldService>()
.ImplementedBy<HelloWorldService>()
.LifeStyle.PerWebRequest
.AsWcfService(
new DefaultServiceModel()
.AddBaseAddresses(baseAddress)
.AddEndpoints(WcfEndpoint.BoundTo(new WSHttpBinding()).At("myBinding"))
.PublishMetadata(o => o.EnableHttpGet())
)
);
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
}
}
}

Categories

Resources