How to consume a Service provided by VSPackage A in VSPackage B? - c#

I have two VSPackages. The first one provides a global service. Both VSPackages consume the service.
The service is defined as explained in MSDN "How To: Register a Service". I left out the ComVisibleAttribute, because the how-to says it's only required if the service needs to be available in unmanaged code, which it doesn't. The interfaces are like
[Guid("5A72348D-617B-4960-B07A-DC6CC5AA7675")]
public interface SMessageBus {}
[Guid("04A499BA-CE09-48AF-96D5-F32DEAF0754C")]
public interface IMessageBus { ... }
The service-providing package follows MSDN "How To: Provide a Service". It looks like:
[<package atttributes>]
[ProvideService(typeof(SMessageBus))]
public sealed class MessageBusProviderPackage : Package
{
public MessageBusProviderPackage()
{
var serviceContainer = this as IServiceContainer;
var serviceCreatorCallback = new ServiceCreatorCallback(CreateMessageBusService);
serviceContainer.AddService(typeof(SMessageBus), serviceCreatorCallback, true);
}
private object CreateMessageBusService(IServiceContainer container, Type serviceType)
{
// this gets called and returns a new bus instance
return (serviceType == typeof(SMessageBus)) ? new MyMessageBus() : null;
}
protected override void Initialize()
{
// this is called after the package was constructed
// the call leads to the service being created by CreateMessageService()
var messageBus = GetService(typeof(SMessageBus)) as IMessageBus;
// the bus is retrieved correctly
...
}
}
This other package is declared like
[<package attributes>]
[ProvideAutoLoad(VSConstants.UICONTEXT.NoSolution_string)]
public sealed class MessageGeneratorPackage : Package
{
protected override void Initialize()
{
// the call below is reached first, in its course the provider is loaded
var service = GetService(type(SMessageBus));
// this point is reached last, but service is null
...
}
}
I debugged through the startup phase and found that the MessageGeneratorPackage gets created and initialized first. This means that the package was sited. When the GetService() call in Initialize() is reached, VS loads my service provider, i.e., the ProvideServiceAttribute correctly marks the MessageBusProviderPackage as provider of the SMessageBus service. The provider package gets instantiated and its Initialize() method gets called, wherein the service is retrieved successfully. Afterwards the initialization of the consumer package continues, but the service request returns null. It seems to me that all requirements stated in MSDN "How To: Troubleshoot Services" are fulfilled. Can anyone tell me what I am missing?

Found the answer myself... the overrides of Initialize() need to call base.Initialize() since that is were registered services actually get promoted to the parent service containers.

Related

FabricException: The primary or stateless instance for the partition

I am following a tutorial from [this book]:
I am getting the following exception:
There's no doubt that my nodes are running fine:
Here's how my stateless service is setup:
internal sealed class MyStatelessService : StatelessService
{
public MyStatelessService(StatelessServiceContext context)
: base(context)
{ }
/// <summary>
/// Optional override to create listeners (e.g., TCP, HTTP) for this service replica to handle client or user requests.
/// </summary>
/// <returns>A collection of listeners.</returns>
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new ServiceInstanceListener[0];
}
/// <summary>
/// This is the main entry point for your service instance.
/// </summary>
/// <param name="cancellationToken">Canceled when Service Fabric needs to shut down this service instance.</param>
protected override async Task RunAsync(CancellationToken cancellationToken)
{
// TODO: Replace the following sample code with your own logic
// or remove this RunAsync override if it's not needed in your service.
long iterations = 0;
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
ServiceEventSource.Current.ServiceMessage(this.Context, "Working-{0}", ++iterations);
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}
}
}
The way I deploy and get this exception:
What am I doing wrong? How can I get my client connected to my cluster?
The entire solution can be viewed here.
Two things:
Your ICalculatorService have to be defined in another library project, in order to be shared between your stateless service library and your client project. So:
Create a new library project MyStatelessService.Interfaces
Add to it NuGet package: Microsoft.ServiceFabric.Services.Remoting
Define in this library your ICalculatorService
Remove ICalculatorService from your other two projects
Add a reference to MyStatelessService.Interfaces to your client application and your stateless service library.
Fix references to ICalculatorService
All your ICalculatorService should be referenced from the same library
Your client will be:
using Microsoft.ServiceFabric.Services.Remoting.Client;
using MyStatelessService.Interfaces;
using System;
static void Main(string[] args)
{
var calculatorClient = ServiceProxy.Create<ICalculatorService>
(new Uri("fabric:/CalculatorService/MyStatelessService"));
var result = calculatorClient.Add(1, 2).Result;
Console.WriteLine(result);
Console.ReadKey();
}
Change your MyStatelessService's Program.cs part after the try statement with this:
ServiceRuntime.RegisterServiceAsync("MyStatelessServiceType",
context => new CalculatorService(context)).GetAwaiter().GetResult();
ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(CalculatorService).Name);
Instead of CalculatorService, you were referencing MyStatelessService.
You're attempting to access your service through remoting, but your service is not enabled for remoting.
You need to return a communication listener from CreateServiceInstanceListeners and implement IService.
When creating your stateless service you called your service MyStatelessService instead of CalculatorService and you called your application CalculatorService instead of CalculatorApplication. As the book states at step 1 under 'The first version' "Create a new Service Fabric application named CalculatorApplication with a service named CalculatorService". You created an application named CalculatorService and a service called MyStatelessService. You then made a new service file within the stateless service project. You should never create a new service within a service. Use the generated service.cs (MyStatelessService.cs in your case) file instead. One way to solve your problem is to copy the implementation of CalculatorService into your stateless service and delete CalculatorService.cs. Your stateless service will be:
internal sealed class MyStatelessService: StatelessService, ICalculatorService
{
public MyStatelessService(StatelessServiceContext serviceContext) : base(serviceContext)
{
}
public Task<int> Add(int a, int b)
{
return Task.FromResult<int>(a + b);
}
public Task<int> Subtract(int a, int b)
{
return Task.FromResult<int>(a - b);
}
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[] { new ServiceInstanceListener(context => this.CreateServiceRemotingListener(context)) };
}
}
However, it's unconventional to call an application 'service', so I'd recommend to create a new project and paste your current implementation into it.
When creating a new project, name your application CalculatorApplication.
And then create the service with the name CalculatorService.
Your CalculatorService.cs file is made automatically, so just paste your current implementation into it. (The same as MyStatelessService above, but with the name CalculatorService.)

Console app with MVC, Ninject and WCF Service (Dispose issue?)

I have a MVC application with all Ninject stuff wired up properly. Within the application I wanted to add functionality to call a WCF service, which then sends bulk messages (i.e. bulk printing) to RabbitMQ queue .
A 'processor' app subscribes to messages in the queue and process them. This is where I also want to update some stuff in the database, so I want all my services and repositories from the MVC app to be available too.
The processor app implements the following:
public abstract class KernelImplementation
{
private IKernel _kernel;
public IKernel Kernel
{
get
{
if (_kernel != null)
return _kernel;
else
{
_kernel = new StandardKernel(new RepositoryModule(),
new DomainModule(),
new ServiceModule(),
new MessageModule());
return _kernel;
}
}
}
}
All Ninject repository bindings are specified within RepositoryModule, which is also used within MVC app and look like this:
Bind<IReviewRepository>().To<ReviewRepository>().InCallScope();
The processor class
public class Processor : KernelImplementation
{
private readonly IReviewPrintMessage _reviewPrintMessage;
public Processor()
{
_reviewPrintMessage = Kernel.Get<IReviewPrintMessage>();
[...]
_bus.Subscribe<ReviewPrintContract>("ReviewPrint_Id",
(reviewPrintContract) => _reviewPrintMessage.ProcessReviewPrint(reviewPrintContract));
//calling ProcessReviewPrint where I want my repositories to be available
}
}
Everything works fine until I update the database from the MVC app or database directly. The processor app doesn't know anything about those changes and the next time it tries to process something, it works on a 'cached' DbContext. I'm sure it's something to do with not disposing the DbContext properly, but I'm not sure what scope should be used for a console app (tried all sort of different scopes to no avail).
The only solution I can think of at the moment is to call WCF service back from the processor app and perform all the necessary updates within the service, but I would want to avoid that.
UPDATE: Adding update logic
Simplified ReviewPrintMessage:
public class ReviewPrintMessage : IReviewPrintMessage
{
private readonly IReviewService _reviewService;
public ReviewPrintMessage(IReviewService reviewService)
{
_reviewService = reviewService;
}
public void ProcessReviewPrint(ReviewPrintContract reviewPrintContract)
{
var review =
_reviewService.GetReview(reviewPrintContract.ReviewId);
[...]
//do all sorts of stuff here
[...]
_reviewService.UpdateReview(review);
}
}
UpdateReview method in ReviewService:
public void UpdateTenancyAgreementReview(TenancyAgreementReview review)
{
_tenancyAgreementReviewRepository.Update(review);
_unitOfWork.Commit();
}
RepositoryBase:
public abstract class EntityRepositoryBase<T> where T : class
{
protected MyContext _dataContext;
protected EntityRepositoryBase(IDbFactory dbFactory)
{
this.DbFactory = dbFactory;
_dbSet = this.DataContext.Set<T>();
}
[...]
public virtual void Update(T entity)
{
try
{
DataContext.Entry(entity).State = EntityState.Modified;
}
catch (Exception exception)
{
throw new EntityException(string.Format("Failed to update entity '{0}'", typeof(T).Name), exception);
}
}
}
Context itself is bound like this:
Bind<MyContext>().ToSelf().InCallScope();
From the description of scopes I thought that Transient scope was the right choice, but as I said earlier I tried all sorts including RequestScope, TransientScope, NamedScope and even Singleton (although I knew it wouldn't be desired behaviour), but none of them seem to be disposing the context properly.
What you'll need is one DbContext instance per transaction.
Now other "applications" like web-applications or wcf-service may be doing one transaction per request (and thus use something like InRequestScope(). Also note, that these application create an object graph for each request. However, that is a concept unknown to your console application.
Furthermore, scoping only affects the instantiation of objects. Once they are instantiated, Scoping does not have any effect on them.
So one way to solve your issue would be to create the (relevant) object tree/graph per transaction and then you could use InCallScope() (InCallScope really means "once per instantiation of an object graph", see here).
That would mean that you'd need a factory for IReviewPrintMessage (have a look at ninject.extensions.factory) and create an instance of IReviewPrintMessage every time you want to execute IReviewPrintMessage.ProcessReviewPrint.
Now you have re-created the "per request pattern".
However, regarding CompositionRoot this is not recommended.
Alternative: you can also only re-create the DbContext as needed. Instead of passing it around everywhere (DbContext as additional parameter on almost every method) you use a SynchronizationContext local storage (or if you don't use TPL/async await: a ThreadLocal). I've already described this method in more detail here

How to create web reference manually

I know that I can point to some SOAP web service by adding web reference using visual studio.
But I need to do it from code.
How can I manually create web reference object in code and access all methods from that object?
Basically I want to avoid generating proxy classes.
If you can get a copy of the service contract (interface)(svcUtil can help with this) then you can include it in your project and use the ChannelFactory class to dynamically create a channel for the client to communicate with the service.
I tend to encapsulate it all up in a SAL (Service Application Layer) to re-use as required.
This is a simple (and in no way complete!) example demonstrating how to connect to a fictious time service and call the GetTime() operation without using a VS generated proxy:
public class TimeSAL : IDisposable
{
private ChannelFactory<ITimeService> timeServiceProxyFactory;
private ITimeService timeServiceProxy;
private ITimeService TimeService
{
get
{
//create channel factory if not there
if (timeServiceProxyFactory == null)
timeServiceProxyFactory = new ChannelFactory<ITimeService>(new BasicHttpBinding(), new EndpointAddress("http://url_to_my_timeservice_endpoint")); //
if (timeServiceProxy == null)
timeServiceProxy = amlProxyFactory.CreateChannel();
return timeServiceProxy;
}
}
public string GetTime()
{
return TimeService.GetTime();
}
public void Dispose()
{
//dispose of ChannelFactory and proxy.
//ensure you check for comm faults to abort before closing
}
}
Now I can use this SAL throughout my code as necessary:
....
using(TimeSAL timeSAL = new TimeSAL())
{
myBusinessObject.CurrentTime = timeSAL.GetTime();
}
....
If you are unable to get your hands on a copy of the service contract, a long-winded way is to handcraft the soap request. Fiddler or soapUI can help with what the message should look like.
Hope some of this helps.

Generic ServiceFactory<T> for WCF Channel Factory and StructureMap with MVC 3

So this will be an interesting post because I must include all my code and will attempt to explain clearly how I have setup my architecture.
I have placed all my Service and DataContracts in a central assembly (DMT.WCF.Contracts). This is done so that the distributed pieces of my application can all reference the same type of service interfaces and contracts which is very nice.
I have setup a StructureMap container to inject my dependencies in the following manner, by specifying a ServiceContext, which will house all of the Service Interface properties so that they can be referenced int he application later.
public interface IServiceContext
{
}
public class ServiceContext: IServiceContext
{
public IAuthenticationService AuthenticationService { get; set; }
public ServiceContext(IAuthenticationService authenticationService)
{
AuthenticationService = authenticationService;
}
}
Then, I have my StructureMapControllerFactory which looks like the following:
public class StructureMapControllerFactory:DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null) return null;
return ObjectFactory.GetInstance(controllerType) as IController;
}
}
and this is configured in my global.asax like the following:
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
Configure();
}
I wanted to decouple my services as much as possible from my appliction, so I have implemented the following ServiceFactory class that handles providing proxies to StructureMap when the IoC container is configured:
public static class ServiceFactory
{
private static readonly ClientSection _clientSection = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;
public static T Create<T>()
{
T context = default(T);
foreach(ChannelEndpointElement endpoint in _clientSection.Endpoints)
{
if(endpoint.Contract == typeof(T).FullName)
{
IEnumerable<Type> assignables = typeof (Binding).Assembly.GetTypes().Where(p => typeof(Binding).IsAssignableFrom(p));
Type bindingType = assignables.Single(p => p.Name.ToLower().Equals(endpoint.Binding.ToLower()));
context = ChannelFactory<T>.CreateChannel((Binding)Activator.CreateInstance(bindingType, false), new EndpointAddress(endpoint.Address));
}
}
return context;
}
}
This allows me to pull directly from the config file when creating proxies so I do not need to select "Add Service Reference" (as that is technically adding a dependency).
In my global.asax, I can now configure my StructureMap Container like this:
protected void Configure()
{
ObjectFactory.Configure(x =>
{
x.Scan(scanner => scanner.AddAllTypesOf<IController>());
x.For<IAuthenticationService>().Use(ServiceFactory.Create<IAuthenticationService>());
x.For<IServiceContext>().Use<ServiceContext>();
});
}
Although I was initially able to use this in the following manner:
IAuthenticationService service = ServiceContext.AuthenticationService.Authenticat(...);
I am now unable to start my application without exceptions being thrown such as the following:
StructureMap configuration failures:
Error: 104
Source: Registry: StructureMap.Configuration.DSL.Registry, StructureMap, Version=2.6.1.0, Culture=neutral, PublicKeyToken=e60ad81abae3c223
Type Instance '685e2e2a-f271-4163-a6fa-ba074e4082d1' (Object: DMT.WCF.Contracts.Authentication.IAuthenticationService) cannot be plugged into type DMT.WCF.Contracts.Authentication.IAuthenticationService, DMT.WCF.Contracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
I am not sure why this is occuring. Like I said, I was initially able to get this up and running, but am not sure what has changed.
I have looked at the many of hundreds of references regarding this error message, but they are all specific to problems that dont seem to match mine, unless I am overlooking my problem.
HELP!!!
Doesn't this operation use the ChannelFactory to new up a channel safe client?
context = ChannelFactory<T>.CreateChannel(
(Binding)Activator.CreateInstance(bindingType, false),
new EndpointAddress(endpoint.Address));
Well, two issues here. As Sixto Saez mentioned, there's WCF issues to consider. On the StructureMap front, my guess is that your factory method may be returning a default instance for an interface.
Two suggestions...
Right after your container configuration, add a call to ObjectFactory.AssertConfigurationIsValid()...make sure you remove it again after you figure out what's wrong :-) it should throw a very similar error, but it will actually try to resolve every instance of every configured type. Usually you'll get a very verbose error with everything that's wrong. You can then start finding where your configuration error is.
It may have something to do with your factory method for the pluggable type. You might try having those instances created on the fly. Use the IContext syntax to do that - context => // Make Foo Here.
protected void Configure()
{
ObjectFactory.Configure(x =>
{
x.Scan(scanner => scanner.AddAllTypesOf<IController>());
// Skip using this
// x.For<IAuthenticationService>()
// .Use(ServiceFactory.Create<IAuthenticationService>());
// Use the IContext syntax instead. Normally you'd grab the instance out of the
// container, but you can use this to resolve an instance "live" from
// somewhere other than the container
x.For<IAuthenticationService>()
.Use(context => ServiceFactory.Create<IAuthenticationService>());
x.For<IServiceContext>().Use<ServiceContext>();
});
// Remove this from production code because it resolves the entire container...
ObjectFactory.AssertConfigurationIsValid();
}
I'm guessing that using the IContext syntax may help fix the configuration errors. You can use the Assert to go from there if not. I think the other comments cover the WCF issues, but it's kind of hard to assess those while StructureMap is misconfigured.

Using Server in Mvc.Controller

I have my own inherited App.Controller from Mvc.Controller which then all of my controllers inherit from. I wrote a provider utilizing an interface and implemented it as MyService and the constructor takes the Server property of Mvc.Controller which is of HttpServerUtilityBase.
However, I instantiate MyService in App.Controller's constructor. The problem is that the Server property of the Controller is null when constructing MyService. I have used public Controller () : base() { } to get the base to be constructed. However, Server remains null.
I would like to avoid Web.HttpContext.Current.Server if possible.
Has any one have a work around for this problem?
Edit: Well, I have implemented tvanfosson's suggestion, and when my app constructs MyService in the property get method, Server is still null.
Edit 2: Nevermind, I was a goof. I had another Controller using Server aswell and did not change that. Case closed.
Use delayed initialization to construct your service.
private MyService service;
public MyService Service
{
get
{
if (this.service == null)
{
this.service = new MyService(this.Server);
}
return this.service;
}
}
Then, your service isn't actually instantiated until it is used in the controller action and by that time the Server property has been set.
I instantiate MyService in App.Controller's constructor.
There's your problem. You need to pass an instance of MyService which has already been constructed into your App.Controller's constructor. Take a look at the Inversion of Control / Dependency Injection patterns, and take a look at some of the libraries which make these patterns easy (see this list).
Why do you need the Server reference? Are you doing stuff like url/html encoding? If so, you could use HttpUtility instead and get rid of the context reference entirely.
This is a very old question, but the subject is still relevant. So, one hint in 2017 that was possibly not available in 2009:
It is true that in the Controller constructor Server is null. But you can use the OnActionExecuting event:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
CurrentServer = Server; // CurrentServer is some instance variable I need later.
}
This works fine for me.
According to this site, if you have this Controller:
public class MyController : Controller
{
private string folderPath;
public MyController()
{
// Throws an error because Server is null
folderPath = Server.MapPath("~/uploads");
// Throws an error because this.ControllerContext is null
folderPath = this.ControllerContext.HttpContext.Server.MapPath("~/uploads");
}
}
Then you want to initialize it this way:
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
// now Server has been initialized
folderPath = Server.MapPath("~/uploads");
}

Categories

Resources