I am getting an exception when I try to start a modified version of the PubSub sample. I am trying to do a few things like making subscription not automatic, and injecting my own ISubscriptionStorage implementation. Here is what I did to MyPublisher\EndpointConfig.cs:
using NServiceBus;
using NServiceBus.Grid.MessageHandlers;
using NServiceBus.ObjectBuilder;
using NServiceBus.Sagas.Impl;
namespace MyPublisher
{
class EndpointConfig : IConfigureThisEndpoint, IWantCustomInitialization
{
public void Init()
{
NServiceBus.Configure.With()
.DefaultBuilder()
.XmlSerializer()
.UnicastBus()
.LoadMessageHandlers(First<GridInterceptingMessageHandler>.Then<SagaMessageHandler>())
.DoNotAutoSubscribe();
NServiceBus.Configure.Instance.Configurer.ConfigureComponent<StreamSubscriptionStorage>(ComponentCallModelEnum.Singleton);
}
}
}
It used to be this:
using NServiceBus;
using NServiceBus.Grid.MessageHandlers;
using NServiceBus.Sagas.Impl;
namespace MyPublisher
{
class EndpointConfig : IConfigureThisEndpoint, AsA_Publisher,
ISpecifyMessageHandlerOrdering
{
public void SpecifyOrder(Order order)
{
order.Specify(First<GridInterceptingMessageHandler>.Then<SagaMessageHandler>());
}
}
}
You forgot to include the .MsmqTransport() in your custom initialization.
Related
I got this type of error when using nservicebus.structuremap. This is my code.
EndPointConfig.cs
namespace NSBus.Server
{
using NServiceBus;
/*
This class configures this endpoint as a Server. More information about how to configure the NServiceBus host
can be found here: http://particular.net/articles/the-nservicebus-host
*/
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, UsingTransport<Msmq>, IWantCustomInitialization
{
public static IBus Bus { get; private set; }
public void Init()
{
ConfigureIocTool();
}
private static void ConfigureIocTool()
{
var container = new Container(y => y.Scan(scan =>
{
scan.TheCallingAssembly();
scan.AssemblyContainingType<SanelibRegistry>();
scan.AssemblyContainingType<CommonRegistry>();
scan.AssemblyContainingType<CoreRegistry>();
scan.WithDefaultConventions();
scan.LookForRegistries();
}));
Bus = Configure.With()
.StructureMapBuilder(container)
.MsmqSubscriptionStorage()
.PurgeOnStartup(false)
.UnicastBus()
.ImpersonateSender(false)
.CreateBus()
.Start(() => Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install());
}
}
}
this code running successfully but i got error after some time.
Since I am using NServiceBus.Host, i don't need to create the bus in your endpoint config:
my initialization becomes something like this:
Since the AsA_Server role is beign used, it already will set the purge queue on startup to false, use unicast bus, etc.
The bus will be created and will be available via DI in all the message handlers.
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, UsingTransport<Msmq>, IWantCustomInitialization
{
public void Init()
{
var container = new Container(y => y.Scan(scan =>
{
scan.TheCallingAssembly();
scan.AssemblyContainingType<SanelibRegistry>();
scan.AssemblyContainingType<CommonRegistry>();
scan.AssemblyContainingType<CoreRegistry>();
scan.WithDefaultConventions();
scan.LookForRegistries();
}));
Configure.With()
.StructureMapBuilder(container)
.MsmqSubscriptionStorage();
}
}
For more details see:
http://particular.net/articles/the-nservicebus-host (section built-in configurations) and also
http://particular.net/articles/containers
Also, for subscription storage, either RavenDB or NHibernate (sql storage) is recommended for production and not msmq.
Hope this helps,
Nikunj Balar
Just wanted to know if there is a way bind a type and resolve a collection. I dont know if Ninject can do this out of the box. I'm using MVC4 with Ninject3 so I have the NinjectWebCommon.cs where I register the services. There is nowhere I can get the kernel (I read that it was bad practice to access the kernel from elsewhere, but that can certainly be the solution to this).
For example, I'm having this class:
public class CacheManager
{
public IEnumerable<SelectListItem> Get<T>() where T : INameValue
I want to be able to send
CacheManager.Get<City>
and obtain the CityRepository class.
Is it this you want to do? :
using System.Collections.Generic;
using System.Linq;
using Ninject;
using Ninject.Modules;
using Ninject.Syntax;
public class Temp
{
public interface ICity { }
public class SelectListItem
{
}
public class FooCity : SelectListItem, ICity { }
public class BarCity : SelectListItem, ICity {}
public class CityModule : NinjectModule
{
public override void Load()
{
this.Bind<ICity>().To<FooCity>();
this.Bind<ICity>().To<BarCity>();
}
}
public class CacheManager
{
private readonly IResolutionRoot resolutionRoot;
public CacheManager(IResolutionRoot resolutionRoot)
{
this.resolutionRoot = resolutionRoot;
}
public IEnumerable<SelectListItem> Get<T>()
{
return this.resolutionRoot.GetAll<T>().OfType<SelectListItem>();
}
}
}
I'm unclear as to whether you have multiple implementations of T (ICity) or one implementation but several instances (like retrieving a list of city names from the database and creating one instance per name). The later you could solve by a this.Bind>().ToProvider(...) binding.
I ended up doing:
In NinjectWebCommon.cs:
kernel.Bind(typeof(CacheManager))
.ToSelf()
.InSingletonScope();
kernel.Bind<IDataListRepository<Locale>>()
.To<LocaleRepository>();
In CacheManager.cs:
public class CacheManager: IDisposable
{
private IKernel kernel;
public CacheManager(IKernel kernel)
{
this.kernel = kernel;
}
public IEnumerable<T> GetAsEnumerable<T>()
{
var rep = kernel.Get<IDataListRepository<T>>();
return rep.GetAll();
}
I don't know if this is bad-practice (since kernel in theory should only be used in the initialization phase), but I didn't find any other way to do it.
If better options exist, please let me know.
Upgrading from version 3 of nservicebus to version 4, and receiving the following error message
"No message serializer has been configured."
stack trace:
at NServiceBus.Unicast.UnicastBus.ValidateConfiguration() in c:\TeamCity\buildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Unicast\UnicastBus.cs:line 866
at NServiceBus.Unicast.UnicastBus.Start(Action startupAction) in c:\TeamCity\buildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Unicast\UnicastBus.cs:line 739
at NServiceBus.Unicast.UnicastBus.Start() in c:\TeamCity\buildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Unicast\UnicastBus.cs:line 718
at CycleMonkey.Inventory.CreateOrder.IT_OPS.CustomInit.Init() in d:\dev\backup\soa_cyclemonkey\Inventory\Inventory.CreateOrder\IT_OPS\CustomInit.cs:line 20
at NServiceBus.Hosting.Configuration.ConfigManager.ConfigureCustomInitAndStartup() in c:\TeamCity\buildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Hosting\Configuration\ConfigurationManager.cs:line 43
at NServiceBus.Hosting.GenericHost.PerformConfiguration() in c:\TeamCity\buildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Hosting\GenericHost.cs:line 126
at NServiceBus.Hosting.GenericHost.Start() in c:\TeamCity\buildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Hosting\GenericHost.cs:line 29
at NServiceBus.Hosting.Windows.WindowsHost.Start() in c:\TeamCity\buildAgent\work\d4de8921a0aabf04\src\hosting\NServiceBus.Hosting.Windows\WindowsHost.cs:line 56
at NServiceBus.Hosting.Windows.Program.<>c_DisplayClassd.b_5(WindowsHost service) in c:\TeamCity\buildAgent\work\d4de8921a0aabf04\src\hosting\NServiceBus.Hosting.Windows\Program.cs:line 76
at Topshelf.Internal.ControllerDelegates1.StartActionObject(Object obj) in c:\Projects\TopShelfForNSB\src\Topshelf\Internal\ControllerDelegates.cs:line 18
at Topshelf.Internal.IsolatedServiceControllerWrapper1.<>c_DisplayClass2.b_1(TService service) in c:\Projects\TopShelfForNSB\src\Topshelf\Internal\IsolatedServiceControllerWrapper.cs:line 65
at Topshelf.Internal.ServiceController1.<.cctor>b__1(ServiceController1 sc) in c:\Projects\TopShelfForNSB\src\Topshelf\Internal\ServiceController.cs:line 35
at Magnum.StateMachine.LambdaAction1.Execute(T instance, Event event, Object parameter) in :line 0
at Magnum.StateMachine.EventActionList1.Execute(T stateMachine, Event event, Object parameter) in :line 0
Has something been missed in the upgrade? Version 3 of code that was working :
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server
{
}
public class CustomInit : IWantCustomInitialization
{
public void Init()
{
Configure.Instance
.CastleWindsorBuilder()
.DefaultBuilder()
.Sagas()
.RunTimeoutManagerWithInMemoryPersistence()
.ConfigureMongoSagaPersister<CreateOrderSagaData>("mongodb://localhost/create-order");
Configure.Instance
.XmlSerializer()
.MsmqSubscriptionStorage()
.MsmqTransport()
.UnicastBus();
}
}
Version 4 of the same code with the suggested changes required with the upgrade
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, UsingTransport<Msmq>
{
}
public class CustomInit : IWantCustomInitialization
{
public void Init()
{
Configure.Features.Enable<Sagas>();
Configure.Serialization.Xml();
Configure.Instance
.CastleWindsorBuilder()
.UseInMemoryTimeoutPersister()
.ConfigureMongoSagaPersister<CreateOrderSagaData>("mongodb://localhost/create-order");
Configure.Instance
.MsmqSubscriptionStorage()
.UnicastBus()
.CreateBus()
.Start();
}
}
When bootstrapping a different container, use the IWantCustomInitialization interface together with the IConfigureThisEndpoint like #JohnSimons mentioned.
Also, when you are implementing the IWantCustomInitialization in the IConfigureThisEndpoint, there is no bus yet, so an instance has not been created at this point, so you'd need to use Configure.With() instead of Configure.Instance.
NOTE: You don't need to specify UsingTransport as Msmq is the default transport.
You also don't need to specify Configure.Serialization.Xml() as Xml is the default serializer.
So, if you change your code to something like below, it should work:
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization
{
public void Init()
{
Configure.Features.Enable<Sagas>();
Configure.With()
.CastleWindsorBuilder()
.UseInMemoryTimeoutPersister()
.MsmqSubscriptionStorage();
}
}
I've been trying to get the Dispose method on my IDisposable WCF service called whilst using Ninject's NinjectServiceHost without any luck. I've then downloaded the Ninject.extensions.WCF example code and tried to get the IDisposable TimeService's Dispose() method to be called, but it does not get called either.
The service is instantiated correctly, just the Dispose() doesn't get called.
Is this a bug or something that myself and the example code are missing?
I've created a stripped down service and testing host that reproduces the issue. The code is below.
I'm using Ninject 3.0.1.10, Ninject.extensions.WCF 3.0.0.5, .net 4.5
ServiceModule.cs code (for setting up bindings)
using Ninject.Modules;
namespace TestNinjectWcf
{
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<Service1>().ToSelf();
// I've also tried Bind<IService1>().To<Service1>()
// and also tried various scopes such as InParent() and InRequestScope()
}
}
}
Console Test Program to start the service.
using System;
using Ninject.Extensions.Wcf;
using Ninject;
using TestNinjectWcf;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel(new ServiceModule());
var service = kernel.Get<NinjectServiceHost<Service1>>();
service.Open();
Console.WriteLine("Service Started");
Console.ReadKey();
service.Close();
}
}
}
Service Implementation
using System;
using System.Diagnostics;
using System.ServiceModel;
namespace TestNinjectWcf
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1, IDisposable
{
public Service1()
{
Debug.WriteLine("Constructor");
}
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public void Dispose()
{
Debug.WriteLine("Dispose"); // This line never gets called!
}
}
}
Maybe it is that you have created singleton service ? (InstanceContextMode.Single)
Only one InstanceContext object is used for all incoming calls and is not recycled subsequent to the calls. If a service object does not exist, one is created
I am new to NServiceBus and struggling to inject IBus in my controller using structure map. Actually after doing a little research i found that we can inject it by putting below code in Application_Start event of global.asax -
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Configure.With()
.Log4Net()
.StructureMapBuilder()
.XmlSerializer()
.MsmqTransport()
.IsTransactional(false)
.PurgeOnStartup(false)
.UnicastBus()
.ImpersonateSender(false)
.CreateBus();
}
and in my controller I can use IBus as property or constructor injection:
private IBus Bus { get; set; }
private ITest Test { get; set; }
public MyLinkController(IBus bus, ITest test)
{
Bus = bus;
Test = test;
}
This works fine and inject bus without any problem. But my problem is I do not have control over global.asax, so i want to put the configuration somewhere else e.g. i tried putting it in structuremap registry like below:
For<IBus>().Use(
() =>
NServiceBus.Configure.With()
.Log4Net()
.StructureMapBuilder()
.XmlSerializer()
.IsTransactional(true)
.PurgeOnStartup(false)
.UnicastBus()
.ImpersonateSender(false)
.CreateBus()
.Start()
);
But it doesn't help. Looks like structure map needs to know the configuration before its own initialization.
So is there any way to do it without application_start event?
I was able to do it through structure-map itself. This is how I changed my structure-map registry:
public ServiceBusRegistry()
{
ForSingletonOf<IBus>().Use(
NServiceBus.Configure.With()
.Log4Net()
.DefaultBuilder()
.XmlSerializer()
.MsmqTransport()
.IsTransactional(false)
.PurgeOnStartup(false)
.UnicastBus()
.ImpersonateSender(false)
.CreateBus()
.Start()
);
}
After putting this in Registry class of structure map, I am able to inject IBus in my controller:
public MyController(IRepository<Test, int> repository, IBus bus)
{
_repository = repository;
_bus = bus;
}
Notice, here I used DefaultBuilder instead of StructureMapBuilder. I may try to improve it in further in future, But as of now its working fine for me.
UPDATED (after our project design changed):
Now we have a startup class in our API project(the project is ASP.NET web API) though we dont use global.asax's Application_start, we are able to put the startup code in this startup class:
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(WebApiPreStartup), "Start", Order = -999)] //make sure we are first
namespace ADP.DS.FrontOffice.Quoting.WebApi
{
public static class WebApiPreStartup
{
public static void Start()
{
GlobalFilterConfig.Configure(GlobalConfiguration.Configuration);
BusConfig.Init();
}
}
}
and the configuration is in separate class:
public static void Init()
{
Configure.Serialization.SystemXml();
Configure.ScaleOut(s => s.UseSingleBrokerQueue());
var configUnicastBus = Configure.With()
.StructureMapBuilder(ObjectFactory.Container)
.UseTransport<NServiceBus.RabbitMQ>()
.PurgeOnStartup(false)
.UnicastBus();
configUnicastBus.SendOnly();
}