IRabbitMqHost autofac registration problem - c#

Need to resolve IRabbitMqHost for adding handler to bus after bus started.
Steps to Reproduce
Register "IRabbitMqHost" in masstransit configuration
Try to resolve "IRabbitMqHost" in autofac
Then "Exception of type 'Autofac.Core.Registration.ComponentNotRegisteredException' was thrown"
builder.Register(context =>
{
var bus = Bus.Factory.CreateUsingRabbitMq(opt =>
{
var result = new List<string>();
Configuration.GetSection("RabbitMq:HostNames").Bind(result);
var host = opt.Host(result[0], Configuration.GetValue<string>("RabbitMq:VirtualHost"), h =>
{
h.Username(Configuration.GetValue<string>("RabbitMq:Username"));
h.Password(Configuration.GetValue<string>("RabbitMq:Password"));
});
builder.Register<IRabbitMqHost>(a => host);
});
return bus;
}).As<IBus>()
.As<IBusControl>();
builder.Build().Resolve<IRabbitMqHost>()
Expected Behavior
Need to resolve IRabbitMqHost which configured in IBus configuration, because need to add handler after bus started.
Need _rabbitMqHost.ConnectReceiveEndpoint()...
Actual Behavior
container.Resolve throws exception belove.
image in https://github.com/MassTransit/MassTransit/issues/1470

When registered to bus in autofac gave delegate function which create bus instance and registers host. But this delegate not invoked yet. After build the containerbuilder and tried to resolve IBus, then it invoke delegate and registered IRabbitMqHost but not built container. Then when i try to solve IRabbitMqHost it not find registered component because added container not built.
this code worked for me;
builder.Register(context =>
{
var bus = Bus.Factory.CreateUsingRabbitMq(opt =>
{
var result = new List<string>();
Configuration.GetSection("RabbitMq:HostNames").Bind(result);
var host = opt.Host(result[0], Configuration.GetValue<string>("RabbitMq:VirtualHost"), h =>
{
h.Username(Configuration.GetValue<string>("RabbitMq:Username"));
h.Password(Configuration.GetValue<string>("RabbitMq:Password"));
});
ContainerBuilder b = new ContainerBuilder();
b.Register<IRabbitMqHost>(a => host).SingleInstance();
b.Update(ApplicationContainer);
});
return bus;
}).As<IBus>()
.As<IBusControl>()
.SingleInstance();
``

Related

ServiceBusConnectionException - Receive Transport faulted

I have the following error when I start the masstransit with azure bus.Start(); on my function StartService() I have configuring my azure with masstransit and autofact. The error:
MassTransit.Azure.ServiceBus.Core.ServiceBusConnectionException
HResult=0x80131500
Message=ReceiveTransport faulted: sb://softbaire-amilkar.servicebus.windows.net/;SharedAccessKeyName=**REMOVED**;SharedAccessKey=**REMOVED**/TeamTimeManager
Source=mscorlib
configuration with masstransit:
public static IContainer ConfigureContainer()
{
var builder = new ContainerBuilder();
builder.AddMassTransit(cfg =>
{
cfg.SetKebabCaseEndpointNameFormatter();
cfg.AddConsumer<TeamTimeManager>();
cfg.UsingAzureServiceBus((context, conf) =>
{
var settings = new HostSettings
{
ServiceUri = new Uri("sb://softbaire-amilkar.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=UeIC0z5RPCt25SjnWdss2ssP5a6msUKNJxmLnBpm26g="),
TokenProvider = TokenProvider.CreateManagedIdentityTokenProvider()
};
conf.Host(settings);
conf.ConfigureEndpoints(context);
});
});
return builder.Build();
}
this is where I start the service and I get the error:
public void StartService()
{
var container = CreatorContainer.ConfigureContainer();
var bus = container.Resolve<IBusControl>();
if (host != null)
{
host.Close();
}
host = new ServiceHost(typeof(TeamTimeManager));
utilHost = new ServiceHost(typeof(TeamTimeUtilityManager));
bus.Start();
source.TraceInformation("Starting TeamTimeManager Azure Bus...");
host.Open();
source.TraceInformation("TeamTimeManager Started!");
utilHost.Open();
utilSource.TraceInformation("Starting TeamTimeUtilityManager...");
}
UPDATE
this problem is solved when I comment on the line:
cfg.AddConsumer<TeamTimeManager>();
if I add a queue or a subscription the problem appears again
BUG
https://github.com/Azure/azure-sdk-for-net/issues/8627
It's likely permissions. MassTransit requires Manage, and you're configuring the managed identity token provider.
Remove the shared access credentials from the connection string, since they would conflict with the managed identity provider.
Make sure the service identity has Manage permissions on the namespace.
Well, the problem was in the token provider.
The problem was that the token generated was connected to azure but without any queue or topic register, the problem started when I wanted to register queues and topics, when I wanted to generate the connection with the queue or a topic I got an error because the token was invalid for my user(weird), so... I changed the method to generate the token and everything started to work correctly.
Before:
var settings = new HostSettings
{
ServiceUri = new Uri("sb://xxxx-busazure.servicebus.windows.net"),
TokenProvider = TokenProvider.CreateManagedIdentityTokenProvider()
};
After: now I'm using CreateSharedAccessSignatureTokenProvider() you need to send as parameters the "SharedAccessKeyName" and the "SharedAccessKey"
var settings = new HostSettings
{
ServiceUri = new Uri("sb://xxxxx-busazure.servicebus.windows.net"),
TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider("RootManageSharedAccessKey", "xxxxxxxxxxxxxxx=")
};
queues and everything is running smoothly, Final configuration method:
public static IContainer ConfigureContainer()
{
var builder = new ContainerBuilder();
builder.AddMassTransit(cfg =>
{
cfg.SetKebabCaseEndpointNameFormatter();
cfg.AddServiceBusMessageScheduler();
cfg.AddConsumer<TeamTimeManager>();
cfg.UsingAzureServiceBus((context, conf) =>
{
conf.UseServiceBusMessageScheduler();
var settings = new HostSettings
{
ServiceUri = new Uri("sb://amilkar-busazure.servicebus.windows.net"),
TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider("RootManageSharedAccessKey", "xxxxxxxxxxxxxxxxxxxxxx")
};
conf.Host(settings);
conf.ReceiveEndpoint("team-time-manager", e =>
{
e.ConfigureConsumer<TeamTimeManager>(context);
});
conf.ConfigureEndpoints(context);
});
});
return builder.Build();
}

.net core 3.0, Service not register using HostBuilder for Integration Tests

The repository is available here: https://github.com/ranouf/TestingWithDotNetCore3_0/tree/WithDatabase
I'm looking for a way to upgrade from .Net Core 2.0 to 3.0 my Integration Tests.
I really try my best to be able to inject a damned service, as you can see, I tried every where I could:
var hostBuilder = new HostBuilder()
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddXunit(Output);
})
.ConfigureServices(services =>
{
services.AddAutofac();
services.AddSingleton<IMyService, MyService>(); //Here
})
.ConfigureContainer<ContainerBuilder>(builder =>
{
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();//Here
})
.ConfigureWebHost(webHost =>
{
// Add TestServer
webHost
.UseStartup<TestStartup>()
.UseTestServer()
.ConfigureServices(services =>
{
services.AddSingleton<IMyService, MyService>();//Here
services.AddAutofac();
services
.AddControllers()
.AddApplicationPart(typeof(TestStartup).Assembly);
})
.ConfigureTestServices(services =>
{
services.AddSingleton<IMyService, MyService>();//Here
services.AddAutofac();
services
.AddControllers()
.AddApplicationPart(typeof(TestStartup).Assembly);
})
.ConfigureTestContainer<ContainerBuilder>(builder =>
{
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();//Here
});
});
But guess what? It doesnt work at all ... I really don't know how I can make the HostBuilder understand ...
Of course I tried to alternativaly keep only one way to inject my service
So when I want to get the Service:
Host = hostBuilder.Start();
Server = Host.GetTestServer();
Client = Host.GetTestClient();
using (var scope = Host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var myService = services.GetRequiredService<MyService>();
}
catch (Exception ex)
{
Output.WriteLine("HOST: " + ex.Message);
}
}
using (var scope = Server.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var myService = services.GetRequiredService<MyService>();
}
catch (Exception ex)
{
Output.WriteLine("SERVER: " + ex.Message);
}
}
The error message is:
The requested service 'MyAPI.Services.MyService' has not been
registered. To avoid this exception, either register a component to
provide the service, check for service registration using
IsRegistered(), or use the ResolveOptional() method to resolve an
optional dependency.
How do you succeed to inject a service in HostBuilder?
You have registered that whenever someone asks for IMyService give them an instance of MyService - but you are asking for MyService directly and DI doesn't know anything about it.
You need to change your registration to:
builder.RegisterType<MyService>().InstancePerLifetimeScope();
Or ask for the interface not the class:
services.GetRequiredService<IMyService>();
Also, you only need to register it in the ConfigureContainer method.

RabbitMQ-MassTransit ReceiveEndPoint not able to listen to the Queue in .net core web APIs

I am using RabbitMQ MassTransit for service bus implementation in my .Net core solution. I have created a queue by the name log.service. After lot many efforts I was finally able to push the messages in the queue and can see them in management tool but when I am listening to the same queue in another microservice project, I am unable to do so. I have pushed the messages in the bus from Authentication service and want to log the event in Logging service. Please help!
Here is my authentication-StartUp.cs
var buildr = new ContainerBuilder();
buildr.RegisterType<LoggingCommandConsumer>();
buildr.Register(c =>
{
return Bus.Factory.CreateUsingRabbitMq(sbc =>
{
var host = sbc.Host(new Uri("rabbitmq://localhost/"), h =>
{
h.Username("guest");
h.Password("guest");
});
sbc.ExchangeType = ExchangeType.Direct;
sbc.ReceiveEndpoint(host, "log.service", e =>
{
e.Consumer<LoggingCommandConsumer>();
});
});
})
.As<IBusControl>()
.As<IBus>()
.As<IPublishEndpoint>()
.SingleInstance();
buildr.Populate(services);
ApplicationContainer = buildr.Build();
return new AutofacServiceProvider(ApplicationContainer);
Here is my logging-StartUp.cs:
var buildr = new ContainerBuilder();
buildr.RegisterType<LoggingCommandConsumer>();
buildr.Register(context =>
{
var busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host(new Uri("rabbitmq://localhost/"), h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.ReceiveEndpoint(host, "log.service", e =>
{
e.Consumer<LoggingCommandConsumer>();
});
});
return busControl;
})
.SingleInstance()
.As<IBusControl>()
.As<IBus>();
buildr.Populate(services);
ApplicationContainer = buildr.Build();
return new AutofacServiceProvider(ApplicationContainer);
Here I am starting the Bus in both the StartUp.CS
var bus = ApplicationContainer.Resolve<IBusControl>();
var busHandle = TaskUtil.Await(() => bus.StartAsync());
lifetime.ApplicationStopping.Register(() => busHandle.Stop());
Here I am sending the message to end points from authentication controller:
var sendToUri = new
Uri("rabbitmq://localhost/log.servicebind=true&queue=log.service");
var endPoint = await _bus.GetSendEndpoint(sendToUri);
await endPoint.Send<ILoggingCommand>(new
{
XCorrelationId = "asd",
M4SId = "M4SId",
Host = "asdasd",
Level = "Level",
Time = "2019-01-02T07:06:43.722Z",
Message = "Message",
Other = "Other"
});
return Ok();
When I try to get the above message in log.service bus in rabbitMQ management tool, I am able to do so...but not able to listen it in logging-startup.cs
Your endpoint has a queue defined by "log.service" + Guid.NewGuid().ToString() but you send messages to the log.service queue.
I don't really see the point of adding the guid to the endpoint address, what are you trying to achieve?
if you define your endpoint as cfg.ReceiveEndpoint(host, "log.service", ep => <configuration> it should work. You need to uncomment your consumer.

Unit Testing IServiceCollection Registration

I'm trying to figure out the easiest way to test my Service Registrations method for my framework. I'm creating dynamic services my registration looks like so:
var messageHubConfig = new DynamicHubServiceConfiguration<Message, MessageDTO>();
messageHubConfig.SetDynamicHubOptions<AstootContext>(async (context, dto) =>
{
return await context.ConversationSubscriptions
.Where(x => x.ConversationId == dto.ConversationId
&& x.IsSubscribed)
.Distinct()
.Select(x => x.User.UniqueIdentifier)
.ToListAsync();
});
messageHubConfig.RequiresDynamicValidator = false;
messageHubConfig.EventMapping.AddCreateEvent(async (sp, obj, dto) =>
{
var conversationService = sp.GetService<IRestEzService<Conversation, ConversationDTO>>();
var conversationDTO = await conversationService.Get(new object[] { dto.ConversationId });
var hubTaskQueue = sp.GetService<IHubServiceTaskQueue>();
hubTaskQueue.QueueDynamicCreate(conversationDTO);
}).When(async (sp, dto) => {
var context = sp.GetService<AstootContext>();
return await context.Conversations.Where(x => x.Id == dto.ConversationId).Where(x => x.Messages.Count == 1).AnyAsync();
});
//Registers service with a hub
restConfiguration.RegisterRestService(typeof(IMessageDTOService),
typeof(MessageDTOService),
messageHubConfig);
Inside of my Register Rest Service Method I have a lot of different services Getting registered e.g:
services.AddTransient(restServiceType, (IServiceProvider serviceProvider) =>
{
var restService = (IRestEzService<TEntity, TDTO>)
ActivatorUtilities.CreateInstance(serviceProvider, restServiceImplementationType);
serviceOption.EventMapping?.Register(serviceProvider, restService);
return restService;
});
How can I be assure that my factory configuration is being registered properly, How can I create a Service Collection for testing?
Create a ServiceCollection,
var services = new ServiceCollection();
call your registration function and then assert that your restServiceType was added.
Next build a provider from the service collection, resolve the restServiceType
var provider = services.BuildServiceProvider();
var restService = provider.GetRequiredService(restServiceType);
and assert that it is created as desired.
The GetRequiredService extension method will throw an exception if the service is unable to resolve the target type.
Now that is based solely on what is currently being shown in your example as I am unaware of any other dependencies.
Based on #Nkosi's answer, a quick test that all Servives are wired up and in a particular order:
// Arrange
var services = new ServiceCollection();
// Act
var provider = services.AddBaseServices(); // Whatever service you have...
// Assert
Assert.AreEqual(27, provider.Count);
// Run this code once and copy the output into this test...
for(int i = 0; i < provider.Count; i++)
{
System.Diagnostics.Debug.WriteLine($"Assert.AreEqual(\"{provider[i].ServiceType.Name}\", provider[{i}].ServiceType.Name);");
}

Autofac and RoutingService

I am trying to build a routing infrastructure and I use Autofac as IoC container. I read the wiki and I know these steps:
ContainerBuilder builder = new ContainerBuilder();
builder.Register(c => new Logger()).As<ILogger>();
builder.Register(c => new EchoService(c.Resolve<ILogger>())).As<IEchoService>();
using (IContainer container = builder.Build())
{
Uri address = new Uri("http://localhost:8080/EchoService");
ServiceHost host = new ServiceHost(typeof(EchoService), address);
host.AddServiceEndpoint(typeof(IEchoService), new BasicHttpBinding(), string.Empty);
host.AddDependencyInjectionBehavior<IEchoService>(container);
host.Description.Behaviors.Add(new ServiceMetadataBehavior {HttpGetEnabled = true, HttpGetUrl = address});
host.Open();
Console.WriteLine("The host has been opened.");
Console.ReadLine();
host.Close();
Environment.Exit(0);
}
I do have this code here to satisfy my scenario:
builder.RegisterType<RoutingService>().As<ISimplexDatagramRouter>().InstancePerLifetimeScope();
builder.Register(c =>
{
var routingConfiguration = new RoutingConfiguration();
routingConfiguration.RouteOnHeadersOnly = false;
return routingConfiguration;
}).As<RoutingConfiguration>();
builder.Register(c =>
{
var publisherServiceHost = new ServiceHost(typeof(RoutingService));
publisherServiceHost.AddServiceEndpoint(typeof(ISimplexDatagramRouter), new NetTcpBinding(), "some address");
publisherServiceHost.Description.Behaviors.Add(new RoutingBehavior(c.Resolve<RoutingConfiguration>()));
return publisherServiceHost;
}).As<ServiceHost>();
This doesn't work, as I get an error from Autofac as it can't find condtructor for RoutingService (its constructor is private).
Do you have any hint?
As far as I know the RoutingService class has no constructors defined. You can see that if you try to do this:
RoutingService rs = new RoutingService();
You will get an error from the compiler saying:
The type System.ServiceModel.Routing.RoutingService has no constructors defined.

Categories

Resources