MassTransit 2.6.1 Request/Response pattern - Response times out - castle-windsor

I'm looking at MassTransit as a ServiceBus implementation to use in a web project.
I am playing with the Request/Response pattern and am seeing a long delay between the consumer receiving the message and responding, and the request publisher handling the response; sometimes, it seems like the response is never going to come through (having left it running for 10 minutes, the response has still not come through). the only times that I have seen the handle delegate get called with the response is after a 30 second timeout period and the timeout exception being thrown; in this situation, the breakpoint set on the handler delegate is hit.
The setup is a standard affair - I have a web app that is publishing requests, a console app that is consuming requests and sending responses, for the web app to handle the responses in the callback.
I'm using Castle Windsor, and the container is initialized in the web project using WebActivator:
[assembly: WebActivator.PreApplicationStartMethod(typeof(BootStrapper), "PreStart")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(BootStrapper), "PostStart")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(BootStrapper), "Stop")]
namespace Web.App_Start
{
public static class BootStrapper
{
internal static IWindsorContainer Container { get; private set; }
public static void PreStart()
{
Container = new WindsorContainer().Install(FromAssembly.This());
}
public static void PostStart()
{
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ApiConfig.Configure(Container);
MvcConfig.Configure(Container);
}
public static void Stop()
{
if (Container != null)
Container.Dispose();
}
}
}
In the web app project (an ASP.NET Web API project), the WindsorInstaller for MassTransit looks like
public class MassTransitInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(AllTypes.FromThisAssembly().BasedOn<IConsumer>());
var bus = ServiceBusFactory.New(configurator =>
{
configurator.UseMsmq();
configurator.VerifyMsmqConfiguration();
configurator.UseMulticastSubscriptionClient();
configurator.ReceiveFrom("msmq://localhost/web");
configurator.EnableMessageTracing();
configurator.Subscribe(x => x.LoadFrom(container));
});
container.Register(Component.For<IServiceBus>().Instance(bus));
}
}
In the console app project, the WindsorInstaller looks like
public class MassTransitInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(AllTypes.FromAssemblyContaining<BasicRequestCommandHandler>().BasedOn<IConsumer>());
var bus = ServiceBusFactory.New(configurator =>
{
configurator.UseMsmq();
configurator.VerifyMsmqConfiguration();
configurator.UseMulticastSubscriptionClient();
configurator.ReceiveFrom("msmq://localhost/console");
configurator.Subscribe(x => x.LoadFrom(container));
});
container.Register(Component.For<IServiceBus>().Instance(bus));
}
}
I have an ApiController with the following GET action method
public class ExampleController : ApiController
{
private readonly IServiceBus _bus;
public HelloController(IServiceBus bus)
{
_bus = bus;
}
// GET api/hello?text={some text}
public Task<IBasicResponseCommand> Get(string text)
{
var command = new BasicRequestCommand {Text = text};
var tcs = new TaskCompletionSource<IBasicResponseCommand>();
_bus.PublishRequest(command, c =>
{
c.Handle<IBasicResponseCommand>(r =>
{
tcs.SetResult(r);
});
});
return tcs.Task;
}
}
BasicRequestCommand and BasicResponseCommand look like so
public interface IBasicRequestCommand
{
Guid CorrelationId { get; set; }
string Text { get; set; }
}
public class BasicRequestCommand :
CorrelatedBy<Guid>, IBasicRequestCommand
{
public Guid CorrelationId { get; set; }
public string Text { get; set; }
public BasicRequestCommand()
{
CorrelationId = Guid.NewGuid();
}
}
public interface IBasicResponseCommand
{
Guid CorrelationId { get; set; }
string Text { get; set; }
}
public class BasicResponseCommand :
CorrelatedBy<Guid>, IBasicResponseCommand
{
public Guid CorrelationId { get; set; }
public string Text { get; set; }
}
And the handler responding to the BasicRequestCommand in the console app:
public class BasicRequestCommandHandler : Consumes<IBasicRequestCommand>.Context
{
public void Consume(IConsumeContext<IBasicRequestCommand> context)
{
Console.Out.WriteLine("received message text " + context.Message.Text);
context.Respond(new BasicResponseCommand { Text = "Hello " + context.Message.Text, CorrelationId = context.Message.CorrelationId });
}
}
I was anticipating with all of this running locally that the request/response would be in the order of a few seconds at most. Am I missing something in configuration?
In addition, I wanted to hook MassTransit up to log4net. I am using Windsor's log4net logging facility and have a log4net section in web.config. This is all working fine for ILogger implementations provided by Windsor (and also for NHibernate logging), but it's not clear from the documentation how to configure MassTransit to use this for logging. Any ideas?

Just as Andrei Volkov and Chris Patterson were discussing on MassTransit google group, it seems that this issue stems from switching MassTransit to using SynchronizationContext, which for some reason does not work as expected.
For the time being one workaround seems to be transitioning to async MassTransit requests, or going back to v2.1.1 that does not use the offending SynchronizationContext.
(Will posts updates on this issue here for posterity if noone else does that first.)

The response timeout issue for Request/Response in ASP.NET is fixed in version 2.6.2.
https://groups.google.com/d/topic/masstransit-discuss/oC1FOe6KsAU/discussion

As you're using the MultiCastSubscriptionClient, you must call SetNetwork(NETWORK_KEY) on each machine (using the same value for NETWORK_KEY). Also, all participating machines need to be on the same subnet - see the documentation at http://masstransit.readthedocs.org/en/latest/overview/subscriptions.html#msmq-multicast
For hooking up log4net, it depends what version you're using, but in the latest versions you include the MassTransit.Log4NetIntegration assembly and then call cfg.UseLog4Net(); in your service bus configuration.
If you're still stuck, you could ask the MT mailing list at https://groups.google.com/forum/?fromgroups#!forum/masstransit-discuss

Related

EFCore 3 with UseLazyLoadingProxies enabled throws System.NotSupportedException: 'Parent does not have a default constructor

I am writting a DDD application and I am trying to use LazyLoading option.
The problem I am facing is that I can run my application OK if I don't use LazyLoading, but once I try to use UseLazyLoadingProxies(), when I get an entity I get the title exception. It seems that is thrown at Castle.DynamicProxies as I can see in the stacktrace
This is my entity:
public class Technology //: Entity
{
// fields
private readonly IList<SubTechnology> subTechnologies = new List<SubTechnology>();
// properties
public long Id { get; private set; }
public virtual TechnologyName Name { get; private set; }
public virtual IReadOnlyList<SubTechnology> SubTechnologies => subTechnologies.ToList().AsReadOnly();
public Technology() { }
public Technology(TechnologyName technologyName) : this()
{
Name = technologyName;
}
//public void AddSubtechnology(SubTechnology subTech)
//{
//}
and this is how I am calling my code:
public sealed class QuestionController
{
private readonly InterviewsDbContext context;
public QuestionController(InterviewsDbContext context)
{
this.context = context;
}
public string GetTechnology(long technologyId)
{
var tech = context.Technology.Single(t => t.Id == technologyId);
return tech?.Name.Value;
}
}
To me is indicating that I don't have my CTOR implemented, but I have tried public, protected, internal and I can't seem to make it work.
The only thing I can tell is that the Domain model do not live in the same assembly that my Context lives... not sure if has to do with the issue..
Any ideas? thx
Well I think I am really stupid, I just transformed my code into something really dumb (anemic model) and the problem went away.
What I figured out was that the backing field being a IList<T> and the Property of type IReadOnlyList<T> and the proxy couln't create the type.
The exception error was not much helpful in this case but changing IList<T> to List<T> fixed my issue.

HttpClient.PostAsJsonAsync content empty

I'm trying to send a complex data type from one process to another using ASP.net MVC. For some reason the receiving end always receives blank (zero/default) data.
My sending side:
static void SendResult(ReportResultModel result)
{
//result contains valid data at this point
string portalRootPath = ConfigurationManager.AppSettings["webHost"];
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(portalRootPath);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage resp = client.PostAsJsonAsync("Reports/MetricEngineReport/MetricResultUpdate", result).Result;
if (!resp.IsSuccessStatusCode) {
//I've confirmed this isn't happening by putting a breakpoint in here.
}
}
My receiving side, in a different class, running in a different process on my local machine:
public class MetricEngineReportController : Controller
{
...
[HttpPost]
public void MetricResultUpdate(ReportResultModel result)
{
//this does get called, but
//all the guids in result are zero here :(
}
...
}
My model is a bit complicated:
[Serializable]
public class ReportResultModel
{
public ReportID reportID {get;set;}
public List<MetricResultModel> Results { get; set; }
}
[Serializable]
public class MetricResultModel
{
public Guid MetricGuid { get; set; }
public int Value { get; set; }
public MetricResultModel(MetricResultModel other)
{
MetricGuid = other.MetricGuid;
Value = other.Value;
}
public MetricResultModel(Guid MetricGuid, int Value)
{
this.MetricGuid = MetricGuid;
this.Value = Value;
}
}
[Serializable]
public struct ReportID
{
public Guid _topologyGuid;
public Guid _matchGuid;
}
Any idea why the data's not arriving?
Any help would be much appreciated...
P.S. For some reason I can't seem to catch the http POST message on fiddler, not sure why that is.
Try using "[FromBody]" parameter in Controller's Action. As you post data is passed to body not in url.
[HttpPost]
public void MetricResultUpdate([FromBody] ReportResultModel result)
{
//this does get called, but
//all the guids in result are zero here :(
}
The problem was twofold:
I needed to specify the type in my JSON post like this:
HttpResponseMessage resp = client.PostAsJsonAsync<MetricResultModel>("Reports/MetricEngineReport/MetricResultUpdate", result.Results[0]).Result;
The components of my model did not have default constructors, which is necessary for the JSON deserialization on the receiving end.
I just had the same problem. It seems that the content-length header is set to 0 when using the default PostAsJsonAsync extension method, which causes the server to ignore the request body.
My solution was to install the System.Net.Http.Json nuget package that uses the new System.Text.Json serializer.
When you add using System.Net.Http.Json;, you should be able to use the new extension method PostAsJsonAsync that works (sets the content-length header) properly.
namespace System.Net.Http.Json
{
public static class HttpClientJsonExtensions
{
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(this HttpClient client, string? requestUri, TValue value, CancellationToken cancellationToken)
{
return client.PostAsJsonAsync(requestUri, value, null, cancellationToken);
}
}
}

View page generates RuntimeBinderException, works anyway

I am trying to use ServiceStack Razor in my project. I set up a very simple DTO:
namespace ModelsWeb.Diagnostics
{
[Route("/echo")]
[Route("/echo/{Text}")]
public class Echo
{
public string Text { get; set; }
}
public class EchoResponse
{
public ResponseStatus ResponseStatus { get; set; }
public string Result { get; set; }
}
}
And a service to go with it:
namespace Rest.Services
{
public class EchoService : Service
{
public object Any(Echo request)
{
return new EchoResponse {Result = request.Text};
}
}
}
Note that the DTO and the service are in different namespaces. This is because I'm building two applications at once -- the server and the thick client -- and I put all the DTOs in a separate class library that they both depend on. This way, the client can reference just that class library, and no other server-side code. I am using Razor to provide a Web interface to some of the server functionality.
Anyway, I also wrote a simple view for my Echo service:
#using ServiceStack.Razor
#using ModelsWeb.Diagnostics
#inherits ViewPage<EchoResponse>
#{
ViewBag.Title = "Echo Response";
Layout = "BasePage";
}
<h1>You typed: #Model.Result</h1>
When I type "http://localhost:62061/echo/hello2" into the browser, I get an error on my log:
Cannot implicitly convert type 'ServiceStack.Razor.Compilation.RazorDynamicObject'
to 'ModelsWeb.Diagnostics.EchoResponse'
However, the template still works, and I see the expected result in the browser. What's going on here ? Am I doing anything wrong ? If not, how can I suppress this exception ?

WcfFacility and Sequence contains no elements error?

I have wcf library with service contracts and implementations.
[ServiceContract]
public interface IServiceProtoType
{
[OperationContract]
Response GetMessage(Request request);
[OperationContract]
String SayHello();
}
[DataContract]
public class Request
{
private string name;
[DataMember]
public string Name
{
get { return name; }
set { name = value; }
}
}
[DataContract]
public class Response
{
private string message;
[DataMember]
public string Message
{
get { return message; }
set { message = value; }
}
}
public class MyDemoService : IServiceProtoType
{
public Response GetMessage(Request request)
{
var response = new Response();
if (null == request)
{
response.Message = "Error!";
}
else
{
response.Message = "Hello, " + request.Name;
}
return response;
}
public string SayHello()
{
return "Hello, World!";
}
}
I have windows service project that references this library, where MyService is just an empty shell that inherits ServiceBase. This service is installed and running under local system.
static void Main()
{
ServiceBase.Run(CreateContainer().Resolve());
}
private static IWindsorContainer CreateContainer()
{
IWindsorContainer container = new WindsorContainer();
container.Install(FromAssembly.This());
return container;
}
public class ServiceInstaller : IWindsorInstaller
{
#region IWindsorInstaller Members
public void Install(IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
string myDir;
if (string.IsNullOrEmpty(AppDomain.CurrentDomain.RelativeSearchPath))
{
myDir = AppDomain.CurrentDomain.BaseDirectory;
}
else
{
myDir = AppDomain.CurrentDomain.RelativeSearchPath;
}
var wcfLibPath = Path.Combine(myDir , "WcfDemo.dll");
string baseUrl = "http://localhost:8731/DemoService/{0}";
AssemblyName myAssembly = AssemblyName.GetAssemblyName(wcfLibPath);
container
.Register(
AllTypes
.FromAssemblyNamed(myAssembly.Name)
.InSameNamespaceAs<WcfDemo.MyDemoService>()
.WithServiceDefaultInterfaces()
.Configure(c =>
c.Named(c.Implementation.Name)
.AsWcfService(
new DefaultServiceModel()
.AddEndpoints(WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(baseUrl,
c.Implementation.Name)
)))), Component.For<ServiceBase>().ImplementedBy<MyService>());
}
#endregion
}
In Client Console app I have the following code and I am getting the following error:
{"Sequence contains no elements"}
static void Main(string[] args)
{
IWindsorContainer container = new WindsorContainer();
string baseUrl = "http://localhost:8731/DemoService/{0}";
container.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero);
container
.Register(
Types
.FromAssemblyContaining<IServiceProtoType>()
.InSameNamespaceAs<IServiceProtoType>()
.Configure(
c => c.Named(c.Implementation.Name)
.AsWcfClient(new DefaultClientModel
{
Endpoint = WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(baseUrl,
c.Name.Substring(1)))
})));
var service1 = container.Resolve<IServiceProtoType>();
Console.WriteLine(service1.SayHello());
Console.ReadLine();
}
I have an idea what this may be but you can stop reading this now (and I apologize for wasting your time in advance) if the answer to the following is no:
Is one (or more) of Request, Response, or MyDemoService in the same namespace as IServiceProtoType?
I suspect that Windsor is getting confused about those, since you are doing...
Types
.FromAssemblyContaining<IServiceProtoType>()
.InSameNamespaceAs<IServiceProtoType>()
... and then configuring everything which that returns as a WCF client proxy. This means that it will be trying to create proxies for things that should not be and hence a Sequence Contains no Elements exception (not the most useful message IMHO but crushing on).
The simple fix would be just to put your IServiceProtoType into its own namespace (I often have a namespace like XXXX.Services for my service contracts).
If that is not acceptable to you then you need to work out another way to identify just the service contracts - take a look at the If method for example or just a good ol' Component.For perhaps.

Asp.Net MVC UNitOfWork and MySQL and Sleeping Connections

I have a MVC web app that is based on the following architecture
Asp.Net MVC2, Ninject, Fluent NHibernate, MySQL which uses a unit of work pattern.
Every connection to MySQL generates a sleep connection that can be seen as an entry in the SHOW PROCESSLIST query results.
Eventually this will spawn enough connections to exeed the app pool limit and crash the web app.
I suspect that the connections are not being disposed correctly.
If this is the case where and how should this happen?
Here is a snapshot of the code that I am using:
public class UnitOfWork : IUnitOfWork
{
private readonly ISessionFactory _sessionFactory;
private readonly ITransaction _transaction;
public ISession Session { get; private set; }
public UnitOfWork(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
Session = _sessionFactory.OpenSession();
Session.FlushMode = FlushMode.Auto;
_transaction = Session.BeginTransaction(IsolationLevel.ReadCommitted);
}
public void Dispose()
{
if (Session != null)
{
if (Session.IsOpen)
{
Session.Close();
Session = null;
}
}
}
public void Commit()
{
if (!_transaction.IsActive)
{
throw new InvalidOperationException("No active transation");
}
_transaction.Commit();
Dispose();
}
public void Rollback()
{
if (_transaction.IsActive)
{
_transaction.Rollback();
}
}
}
public interface IUnitOfWork : IDisposable
{
void Commit();
void Rollback();
}
public class DataService
{
int WebsiteId = Convert.ToInt32(ConfigurationManager.AppSettings["Id"]);
private readonly IKeyedRepository<int, Page> pageRepository;
private readonly IUnitOfWork unitOfWork;
public PageService Pages { get; private set; }
public DataService(IKeyedRepository<int, Page> pageRepository,
IUnitOfWork unitOfWork)
{
this.pageRepository = pageRepository;
this.unitOfWork = unitOfWork;
Pages = new PageService(pageRepository);
}
public void Commit()
{
unitOfWork.Commit();
}
}
public class PageService
{
private readonly IKeyedRepository<int, Page> _pageRepository;
private readonly PageValidator _pageValidation;
public PageService(IKeyedRepository<int, Page> pageRepository)
{
_pageRepository = pageRepository;
_pageValidation = new PageValidator(pageRepository);
}
public IList<Page> All()
{
return _pageRepository.All().ToList();
}
public Page FindBy(int id)
{
return _pageRepository.FindBy(id);
}
}
Your post does not give any information in which scope UoW's are created.
If it is transient. It won't be disposed at all and this is up to you.
In case of InRequestScope it will be disposed after the GC has collected the HttpContext. But as I told Bob recently in the Ninject Mailing List it is possible to release all objects in the end request event handler of the HttpApplication. I'll add support for this in the next release of Ninject.
I did some investigation into the root cause of this problem. Here is a bit more information and possible solutions:
http://blog.bobcravens.com/2010/11/using-ninject-to-manage-critical-resources/
Enjoy.
Ninject makes no guarantees about when and where your IDisposables will be Disposed.
Read this post from the original Ninject man
I'd also suggest having a look around here, this has come up for various persistence mechanisms and various containers - the key thing is you need to take control and know when you're hooking in the UOW's commit/rollback/dispose semantics and not leave it to chance or cooincidence (though Convention is great).