NServicebus DataBus - nservicebus

I need to move some large files, and I wanted to use NserviceBus as the files are not persisted on the system. I have been trying to get this up and running using the new databus feature in v.3.
The files are generated in one process, then passed onto the bus. My problem is that I can't get the bus started. I have a sample application below that basically mirrors my set up, except that in the 'real' application, the bus lives in a different application (not pushed to a server yet so I just run a dev instance)
#region Declarations
private IBus Bus { get; set; }
#endregion
#region Constructors
public Sender()
{
if (Directory.Exists(BasePath))
{
Bus = Configure.Instance
.FileShareDataBus(BasePath)
.UnicastBus().DoNotAutoSubscribe()
.CreateBus()
.Start();
}
}
#endregion
#region Methods
public void SendMessage()
{
// get a list of file names
List<string> fileList = Directory.GetFiles(#"c:\test\").ToList();
Bus.Send<GenericListMessage>(message =>
{
message.Name = "TEST";
message.FileList = new DataBusProperty<List<string>>(fileList);
});
}
#endregion
My EndpointConfig.cs looks like this:
public class EndpointConfig : IConfigureThisEndpoint, AsA_Client
{
}
internal class SetupDataBus : IWantCustomInitialization
{
public static string BasePath = #"c:\storage\";
public void Init()
{
Configure.Instance
.FileShareDataBus(BasePath)
.UnicastBus()
.DoNotAutoSubscribe();
}
}
I have changed my code in the Sender class to send a non-Databus message, and a simple message, and this worked fine. But when I try to use it to send a Databus message I keep getting a NullReferenceException for the bus. If anyone can give me a pointer I would really appreciate it.

You need to change
private IBus Bus { get; set; }
to:
public IBus Bus { get; set; }
To get dependecy injection for the bus.

Related

How to write data to the Orchard CMS repository from a non HTTP thread

I have an Orchard CMS module that loads up some code which provides service functions. The service code is written to be host agnostic and has been used with ASP.NET and WCF previously. The service code uses MEF to load plugins. One such plugin is for audit.
In an attempt to allow access to the Orchard database for audit I have modified the service code to also allow the host to pass in an audit implementation instance. Thus my Orchard module can pass in an instance when the service starts with the intention that this instance writes audit data as records in the Orchard DB.
I have created a migration for my database:
public int UpdateFrom5()
{
SchemaBuilder.CreateTable("AuditRecord",
table => table
.Column<int>("Id", c => c.PrimaryKey().Identity())
.Column<int>("AuditPoint")
.Column<DateTime>("EventTime")
.Column("CampaignId", DbType.Guid)
.Column("CallId", DbType.Guid)
.Column<String>("Data")
);
return 6;
}
I have created my AuditRecord model in Models:
namespace MyModule.Models
{
public class AuditRecord
{
public virtual int Id { get; set; }
public virtual int AuditPoint { get; set; }
public virtual DateTime EventTime { get; set; }
public virtual Guid CampaignId { get; set; }
public virtual Guid CallId { get; set; }
public virtual String Data { get; set; }
}
}
I have added an IAuditWriter interface that derives from IDependency so that I can inject a new instance when my module starts.
public interface IAuditWriter : IDependency
{
void WriteAuditRecord(AuditRecord data);
}
For my audit writer instance to work with the existing service code it must be derived from an abstract class FlowSinkAudit defined in the service library. The abstract class defines the Audit method. When the service needs to write audit it calls the audit method on all instances derived from the FlowAuditSink abstract class that have been instantiated either through MEF or by passing in an instance at startup.
public class AuditWriter : FlowAuditSink, IAuditWriter
{
private readonly IComponentContext ctx;
private readonly IRepository<AuditRecord> repo;
public AuditWriter(IComponentContext ctx, IRepository<AuditRecord> repo)
{
this.ctx = ctx;
this.repo = repo;
}
public void WriteAuditRecord(AuditRecord data)
{
// Get an audit repo
//IRepository<AuditRecord> repo = (IRepository<AuditRecord>)ctx.Resolve(typeof(IRepository<AuditRecord>));
using (System.Transactions.TransactionScope t = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Suppress))
{
this.repo.Create(data);
}
}
public override void Audit(DateTime eventTime, AuditPoint auditPoint, Guid campaignId, Guid callId, IDictionary<String, Object> auditPointData)
{
// Add code here to write audit into the Orchard DB.
AuditRecord ar = new AuditRecord();
ar.AuditPoint = (int)auditPoint;
ar.EventTime = eventTime;
ar.CampaignId = campaignId;
ar.CallId = callId;
ar.Data = auditPointData.AsString();
WriteAuditRecord(ar);
}
}
My service code is started from a module level class that implements IOrchardShellEvents
public class Module : IOrchardShellEvents
{
private readonly IAuditWriter audit;
private readonly IRepository<ServiceSettingsPartRecord> settingsRepository;
private readonly IScheduledTaskManager taskManager;
private static readonly Object syncObject = new object();
public ILogger logger { get; set; }
public Module(IScheduledTaskManager taskManager, IRepository<ServiceSettingsPartRecord> settingsRepository, IAuditWriter audit)
{
this.audit = audit;
this.settingsRepository = settingsRepository;
this.taskManager = taskManager;
logger = NullLogger.Instance;
}
...
When the service is started during the "Activated" event, I pass this.Audit to the service instance.
public void Activated()
{
lock (syncObject)
{
var settings = settingsRepository.Fetch(f => f.StorageProvider != null).FirstOrDefault();
InitialiseServer();
// Auto start the server
if (!StartServer(settings))
{
// Auto start failed, setup a scheduled task to retry
var tasks = taskManager.GetTasks(ServerAutostartTask.TaskType);
if (tasks == null || tasks.Count() == 0)
taskManager.CreateTask(ServerAutostartTask.TaskType, DateTime.Now + TimeSpan.FromSeconds(60), null);
}
}
}
...
private void InitialiseServer()
{
if (!Server.IsInitialized)
{
var systemFolder = #"C:\Scratch\Plugins";
if (!Directory.Exists(systemFolder))
Directory.CreateDirectory(systemFolder);
var cacheFolder = System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/MyModule/Cache");
if (!Directory.Exists(cacheFolder))
Directory.CreateDirectory(cacheFolder);
Server.Initialise(systemFolder, cacheFolder, null, (FlowAuditSink)audit);
}
}
All of this works as expected and my service code calls the audit sink.
My problem is that when the audit sink is called and I try to write the audit to the database using this.repo.Create(data) nothing is written.
I have also attempted to create a new repository object by using the IComponentContext interface but this errors with object already disposed. I assume this is because the audit sink is a long lived object instance.
I have attempted both with and without the current transaction suspended which doesn't affect the result. I assume this is because the call is not coming through ASP.NET MVC but from a thread created by the service code.
Can anyone tell my how I can get my audit data to appear in the Orchard database?
Thanks
Chris.
Well, I have a solution, but as I'm not very familiar with Orchards architecture it may not be the best way.
After a good deal of delving into the Orchard sources it struck me that the crux of this issue can be summarised as
"how do I access the Orchard autofac injection mechanism from a thread that does not use the Http request pipeline".
I figured that this is what a scheduled task must do so I created a scheduled task and set a breakpoint in IScheduledTaskHandler.Process to discover how the task was executed. Looking at Orchard\Tasks\SweepGenerator.cs showed me the way.
I modified my AuditWriter thusly:
public interface IAuditWriter : ISingletonDependency
{
}
public class AuditWriter : FlowAuditSink, IAuditWriter
{
private readonly IWorkContextAccessor _workContextAccessor;
public AuditWriter(IWorkContextAccessor workContextAccessor)
{
_workContextAccessor = workContextAccessor;
}
public override void Audit(DateTime eventTime, AuditPoint auditPoint, Guid campaignId, Guid callId, IDictionary<String, Object> auditPointData)
{
// Add code here to write audit into the Orchard DB.
AuditRecord ar = new AuditRecord();
ar.AuditPoint = (int)auditPoint;
ar.EventTime = eventTime;
ar.CampaignId = campaignId;
ar.CallId = callId;
ar.Data = auditPointData.AsString();
using (var scope = _workContextAccessor.CreateWorkContextScope())
{
// resolve the manager and invoke it
var repo = scope.Resolve<IRepository<AuditRecord>>();
repo.Create(ar);
repo.Flush();
}
}
}
scope.Resolve works and my data is successfully written to the Orchard DB.
At the moment, I don't think my use of ISingletonDependency is working correctly as my constructor is only called when my module injects an AuditWriter instance in its constructor and it happens more than once.
Anyway it seems that to gain access to the Orchard autofac resolution mechanism from a non Http thread we use IWorkContextAccessor
Please let me know if this is not correct.

Return Entity Framework objects over WCF

We have a problem concerning Entity Framework objects and sending them through WCF.
We have a database, and Entity Framework created classes from that database, a 'Wallet' class in this particular situation.
We try to transfer a Wallet using this code:
public Wallet getWallet()
{
Wallet w = new Wallet();
w.name = "myname";
w.walletID = 123;
return w;
}
We need to transfer that Wallet class, but it won't work, we always encounter the same exception:
"An error occurred while receiving the HTTP response to localhost:8860/ComplementaryCoins.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details."
We searched on the internet, and there is a possibility that the error is due to the need of serialization of Entity Framework-objects.
We have absolutely no idea if this could be the case, and if this is the case, how to solve it.
Our DataContract looks like this (very simple):
[DataContract]
public partial class Wallet
{
[DataMember]
public int getwalletID { get { return walletID; } }
[DataMember]
public string getname { get { return name; } }
}
Does anyone ever encountered this problem?
EDIT: Our Entity Framework created class looks like this:
namespace ComplementaryCoins
{
using System;
using System.Collections.Generic;
public partial class Wallet
{
public Wallet()
{
this.Transaction = new HashSet<Transaction>();
this.Transaction1 = new HashSet<Transaction>();
this.User_Wallet = new HashSet<User_Wallet>();
this.Wallet_Item = new HashSet<Wallet_Item>();
}
public int walletID { get; set; }
public string name { get; set; }
public virtual ICollection<Transaction> Transaction { get; set; }
public virtual ICollection<Transaction> Transaction1 { get; set; }
public virtual ICollection<User_Wallet> User_Wallet { get; set; }
public virtual ICollection<Wallet_Item> Wallet_Item { get; set; }
}
}
Thanks for helping us.
I had the same problem some time ago and the solution for this was:
The entity framework was returning a serialized class instead of normal class.
eg. Wallet_asfawfklnaewfklawlfkawlfjlwfejlkef instead of Wallet
To solve that you can add this code:
base.Configuration.ProxyCreationEnabled = false;
in your Context file.
Since the context file is auto generated you can add it in the Context.tt
In the Context.tt file it can be added around lines 55-65:
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
public <#=code.Escape(container)#>()
: base("name=<#=container.Name#>")
{
base.Configuration.ProxyCreationEnabled = false;
<#
if (!loader.IsLazyLoadingEnabled(container))
{
#>
this.Configuration.LazyLoadingEnabled = false;
<#
Try specifying a setter for the properties, something like this :
[DataContract]
public partial class Wallet
{
[DataMember]
public int getwalletID { get { return walletID; } set { } }
[DataMember]
public string getname { get { return name; } set { } }
}
If it still doesn't work, you may consider creating an intermediate POCO class for this purpose, and use mapper library like AutoMapper or ValueInjecter to transfer the data from the EF objects.
The POCO class should have same properties as your EF class :
[DataContract]
public class WalletDTO
{
[DataMember]
public int walletID { get; set; }
[DataMember]
public string name { get; set; }
}
And modify your method to return this class instead :
public WalletDTO getWallet()
{
Wallet w = new Wallet(); // or get it from db using EF
var dto = new WalletDTO();
//assuming we are using ValueInjecter, this code below will transfer all matched properties from w to dto
dto.InjectFrom(w);
return dto;
}
Are you trying to recieve a IEnumerable<Wallets>? If - yes, please modify your server class that returns the IEnumerable by adding .ToArray() method

Is there a reliable way to scope Ninject bound services to an NServicebus message handler?

I want to bind my Entity Framework context to be scoped per NServicebus message. Would the following code successfully do that?
Bind<IDbContext>().To<MyContext>()
.InScope(x => x.Kernel.Get<IBus>().CurrentMessageContext.Id);
Background
I have a NServicebus service that has several IMessageHandlers that read IEvents off an MSMQ Queue.
Each handler converts the message and saves it to a MS SQL Database by way of a particular IRepository sitting over an Entity Framework context.
The repositories needed by each handler are injected via ninject using NServicebus.ObjectBuilder.Ninject
public class Product
{
public string Code { get; set; }
public Category Category { get; set; }
}
public class Category
{
public string Code { get; set; }
}
public class SampleContext : IDbContext
{
IDbSet<Product> Products { get; }
IDbSet<Category> Categories{ get; }
}
public class ProductRepository : IProductRepository
{
private IDbContext _context;
public ProductRepository(IDbContext ctx) { _context = ctx; }
public void Add(Product p)
{
_context.Products.Add(p);
_context.SaveChanges();
}
}
public class CategoryRepository : ICategoryRepository
{
private IDbContext _context;
public CategoryRepository (IDbContext ctx) { _context = ctx; }
public Category GetByCode(string code)
{
return _context.Categories.FirstOrDefault(x => x.Code == code);
}
}
public class AddProductMessageHandler : IMessageHandler<IAddProductEvent>
{
private IProductRepository _products;
private ICategoryRepository _categories;
public AddProductMessageHandler(IProductRepository p, ICategoryRepository c)
{
_products = p;
_categories = c;
}
public void Handle(IAddProductEvent e)
{
var p = new Product();
p.Code = e.ProductCode;
p.Category = _categories.GetByCode(e.CategoryCode);
_products.Add(p);
}
}
Issue
If the EF context is bound in Transient scope (default) then each bound repository in the handler has it's own instance of the context.
Bind<IDbContext>().To<SampleContext>();
This causes issues if I load an object from one repository and then save it via another.
Likewise, if it's bound in Singleton scope, then the same context is used by all repositories, but then it slowly fills up with tracked changes and goobles up all my ram (and gets slower and slower to boot).
Bind<IDbContext>().To<SampleContext>().InSingletonScope();
Question
Ideally I would like each message handler to have 1 EF context that all required repositories (of that handler) use to load and save entities.
Is scoping the context to the current messages Id property a safe/reliable/good way of doing this?
Bind<IDbContext>().To<SampleContext>()
.InScope(x => x.Kernel.Get<IBus>().CurrentMessageContext.Id);
See my blogpost here which describes the scoping apart from NSB 4.0
http://www.planetgeek.ch/2013/01/16/nservicebus-unitofworkscope-with-ninject/
If you have 3.0 you can look into the current develop branch and port the extension methods to your code. You only have to change the scope name.
I'm not familiar with EF Context so please disregard if the answer below does not make any sense.
If EF Context is similar to a NH ISession, then I think the better option is to use a UoW the same way as NH implementation.
You can read more about UoW here.

OData / WCF Data Service not working with complex type

I'm brand new to OData and WCF data services so this might be an easy problem. I'm using VS Web Developer Express 2010 where I have a very simple WCF Data Service hosted in a console app. It's returning an IQuerable collection of a simple 'Study' class from a repository (located in a separated dll project), which in turn retrieves 'Study' classes from a db project in another dll (so 3 projects in the solution).
I also have an 'Experiment' class in the db project and there can be multiple Experiments in a Study. When I exclude the Experiment class from the Study everything works and I get data coming back. The problem happens when I add a List collection to the Study class, then I get a runtime error when I try to run the service. In Firebug the error is '500 Internal Server Error', and the message in the browser is 'Request Error. The server encountered an error processing the request. See server logs for more details.'
I have IIS 7 and I also just installed IIS 7.5 but again it's brand new to me, so I can't figure out where the service is hosted or where to view the server / web logs. There are only IIS 7 logs visible in 'C:\inetpub\logs\LogFiles\W3SVC1'. The VS web server (Cassini) doesn't start when I run the app, so this suggests it's being hosted in IIS 7.5 (?).
So
- how do I return child classes / complex objects?
- how do I know where my service is hosted and where can I find the server logs?
Here's the host app:
using MyStudyRepository;
using MyStudyDB;
namespace MyStudyService
{
public class Program
{
public static void Main(string[] args)
{
string serviceAddress = "http://localhost:998";
Uri[] uriArray = { new Uri(serviceAddress) };
Type serviceType = typeof(StudyDataService);
using (var host = new DataServiceHost(serviceType,uriArray))
{
host.Open();
Console.WriteLine("Press any key to stop service");
Console.ReadKey();
}
}
}
public class StudyDataService : DataService<StudyRepository>
{
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
}
}
}
Here's the repository:
using MyStudyDB;
namespace MyStudyRepository
{
public class StudyRepository
{
List<Study> _List = new List<Study>();
//Add constructor to populate myStudies list on creation of class
public StudyRepository()
{
for (int i = 1; i < 5; i++)
{
Study myStudy = new Study() { ID = i, StudyOwnerId = i, StudyName = "Study" + i.ToString() /*, Experiments = null */ };
_List.Add(myStudy);
}
}
public IQueryable<Study> Studies
{
get
{
return _List.AsQueryable<Study>();
}
}
}
}
And here's the DB:
namespace MyStudyDB
{
public class Study
{
public int ID { get; set;}
public int StudyOwnerId { get; set; }
public string StudyName { get; set; }
//public List<Experiment> Experiments { get; set; }
}
public class Experiment
{
public int ID { get; set; }
public string Name { get; set; }
public int StudyId { get; set; }
}
}
To debug the WCF Data Service please refer to this blog post: http://blogs.msdn.com/b/phaniraj/archive/2008/06/18/debugging-ado-net-data-services.aspx
As to why the collection of Experiment doesn't work, there are two reasons:
The Experiment class is not recognized as an entity type because there's no entity set for it. (Entity set is the IQueryable property on your repository class, which you don't have). As a result the Experiment class is only recognized as a complex type.
The currently released version of WCF Data Services doesn't support MultiValues, MultiValue is effectively a collection of primitive or complex types.
So you have two way to "fix" this. Either make sure that Experiment is in fact an entity, by adding IQueryable property on your repository class.
Or use the latest CTP (http://blogs.msdn.com/b/astoriateam/archive/2011/06/30/announcing-wcf-data-services-june-2011-ctp-for-net4-amp-sl4.aspx) which does support MultiValues.
Thanks! And I guess it is missing the DataServiceKey attribute on the class as follows:
[DataServiceKey("ID")]
public class Study
{
.....
}

Impossible to have two sagas that handle the same message type

I have 2 different sagas (I mean saga types) that handle the same message.
public class AttachMessageToBugSaga : TpSaga<AttachMessageToBugSagaData>, IAmStartedByMessages<MessageIsNotAttached>, IHandleMessages<MessageAttachedToGeneralMessage>
{
public override void ConfigureHowToFindSaga()
{
ConfigureMapping<MessageAttachedToGeneralMessage>(
saga => saga.Id,
message => message.SagaId
);
}
public void Handle(MessageIsNotAttachedToBug message)
{
Send(new AttachMessageToGeneralCommand { MessageId = 66, GeneralId = 13 });
}
public void Handle(MessageAttachedToGeneralMessage message)
{
//do some stuf fhere
}
}
public class AttachMessageToBugSagaData : IContainSagaData
{
public Guid Id { get; set; }
public string Originator { get; set; }
public string OriginalMessageId { get; set; }
}
public class AttachMessageToRequestSaga : TpSaga<AttachMessageToRequestSagaData>, IAmStartedByMessages<MessageIsNotAttachedToRequest>, IHandleMessages<MessageAttachedToGeneralMessage>
{
public override void ConfigureHowToFindSaga()
{
ConfigureMapping<MessageAttachedToGeneralMessage>(
saga => saga.Id,
message => message.SagaId
);
}
public void Handle(MessageIsNotAttachedMessageToRequest message)
{
//do some stuff here
}
public void Handle(MessageAttachedToGeneralMessage message)
{
//do some stuff here
}
}
public class AttachMessageToRequestSagaData : IContainSagaData
{
public Guid Id { get; set; }
public string Originator { get; set; }
public string OriginalMessageId { get; set; }
}
When I run the sample I get an exception :
System.InvalidCastException: Unable to cast object of type 'MyCustomPlugin.AttachMessageToGeneralSagaData' to type 'MyCustomPlugin.AttachMessageToRequestSagaData'.
I understand why it happens, but I still need some workaround. I tried to implement my own IFindSagas class :
public class SagaFinder : IFindSagas<AttachMessageToGeneralSagaData>.Using<MessageAttachedToGeneralMessage>,
IFindSagas<AttachMessageToRequestSagaData>.Using<MessageAttachedToGeneralMessage>,
IFindSagas<AttachMessageToRequestSagaData>.Using<MessageIsNotAttachedToRequest>,
IFindSagas<AttachMessageToRequestSagaData>.Using<MessageIsNotAttachedToBug>
{
AttachMessageToGeneralSagaData IFindSagas<AttachMessageToGeneralSagaData>.Using<MessageAttachedToGeneralMessage>.FindBy(MessageAttachedToGeneralMessage message)
{
return ObjectFactory.GetInstance<AttachMessageToGeneralSagaData>();
}
AttachMessageToRequestSagaData IFindSagas<AttachMessageToRequestSagaData>.Using<MessageAttachedToGeneralMessage>.FindBy(MessageAttachedToGeneralMessage message)
{
return ObjectFactory.GetInstance<AttachMessageToRequestSagaData>();
}
public AttachMessageToRequestSagaData FindBy(MessageIsNotAttachedToRequest message)
{
return new AttachMessageToRequestSagaData();
}
public AttachMessageToRequestSagaData FindBy(MessageIsNotAttachedToBug message)
{
return new AttachMessageToRequestSagaData();
}
}
But I do not get into my finders for "MessageAttachedToGeneralMessage".
Please tell me if there is some other workaround, or how to make this example working.
I'm not sure that having more than one Saga within the same process boundary works very well - at least, I've had problems with it too. It's probably better (in general) to have Sagas separated into two different processes anyway, because otherwise it would cause a lot of locking and potentially deadlocks on your saga storage.
Is your message that is handled by 2 Sagas Sent or Published? If it's published (or can be made to), it would be easy to separate the Sagas into two separate assemblies. Just be sure to manually call Bus.Subscribe() for the message type in each Saga, since Sagas don't auto-subscribe to messages listed in the app.config.
If your message is Sent, and there's nothing you can do to change it, then create a central handler for your existing message type that either Publishes a second message type to go to both Sagas, or Sends two separate messages to each saga.
Finally (after digging into the source code) I've found the solution. It seems the only way is to implement my own SagaPersister, where I can do anything I want.
Default implementation in NserviceBus of InMemorySagaPersister has the following code :
T ISagaPersister.Get<T>(Guid sagaId)
{
ISagaEntity result;
data.TryGetValue(sagaId, out result);
return (T)result;
}
And exception occurs while casting .