Define NServiceBus instance-mapping in code - c#

I'm writing an asp.net core application and wanna send a message to an NServiceBus endpoint.
As we have different environments I need to configure an endpoint address for each environment. I do that in the app settings.Env.json.
I like to do the same with the instance mappings. The only ways I know is to have a different instance-mapping.xml file for every environment or add it to the app.config that I don't have. Is there a way to set the instance machine in code? I don't wanna have different XML files.
I use NServiceBus 6.3.4

I added a feature to the endpoint configuration:
endpointConfiguration.EnableFeature<MyFeature>();
public class MyFeature : Feature
{
protected override void Setup(FeatureConfigurationContext context)
{
var endpointInstances = context.Settings.Get<EndpointInstances>();
endpointInstances.AddOrReplaceInstances("InstanceMapping",
new List<EndpointInstance>
{
new EndpointInstance("MyEndpoint").AtMachine("VM-1")
});
}
}
Check docs here and here

Related

Routes in AspNetCore.TestHost depend on Startup.cs location?

I am trying to test my ASP.NET Core Web Application with Microsoft.AspNetCore.TestHost. It works fine this way (result has status 200):
var server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
var client = server.CreateClient();
var result = await client.GetAsync(someRequestUrl);
In this case the real Startup class from the API project is used.
However, I don't want to use the real Startup class in my integration test. The main reason is the need to mock some stuff that gets wired during application startup. For example, the database server to be used. It can be done in a very elegant way by defining a virtual method in Startup.cs:
public virtual void SetupDbContext(IServiceCollection services)
{
services.AddDbContext<TbsDb>(options =>
options.UseSqlServer("someConnectionString"));
}
Then I create a new class, which inherits from the original Startup class and overrides this method to use Sqlite, in-memory database or whatever:
public override void SetupDbContext(IServiceCollection services)
{
services.AddDbContext<TbsDb>(
options => options.UseSqlite("someConnectionString"));
}
This also works well with TestHost if the new class is in the same API project.
Obviously, I don't want this class which is used for testing to be there. But if I move it to integration tests project and create a TestServer there, the same test fails because the result has status 404. Why is it happening? It still inherits from the Startup class, which is in the API project. Thus I expect all the routes to work the same no matter where the TestStartup class is. Can it be solved somehow?

Exposing hangfire without auth

Is there a way to expose Hangfire in IIS without having to configure authorization?
In this specific case the dashboard should be open, but when accessing it (not in debug) it returns a 401 code.
I think you should be able to write a custom implementation of IDashboardAuthorizationFilter as described in the documentation. Be aware that the default is only local requests to the dashboard are allowed. It's also recommended that you really use authorization and do not publish unauthorized dashboards as it contains sensitive information.
If you still want to do it, try:
Custom DashboardAuthorizationFilter
public class MyAuthorizationFilter : IDashboardAuthorizationFilter
{
public bool Authorize(DashboardContext context)
{
return true;
}
}
Use it in the configuration of hangfire
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new [] { new MyAuthorizationFilter() }
});

Branching OWIN pipeline based on hostname

With OWIN (specifically Katana) it is possible to configure applications to different branches. For example:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/branch1", branch1 => branch1.UseMiddlewareA());
app.Map("/branch2", branch2 => branch2.UseMiddlewareB());
app.UseDefaultMiddleware();
}
}
Is it possible to achieve the same thing based on host name rather than route path? So for exampl, say you have www.mydomain.com/blog configured with app.Map("/blog", blog => blog.UseBlog()); Instead of this, you want to use blog.mydomain.com. Both blog.mydomain.com and www.mydomain.com point to the same web application, but for the blog sub-domain, I want it to use a different app configuration within the OWIN pipeline.
Many thanks for any help.
Yes, you can do this with MapWhen.
http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin/Mapping/MapWhenExtensions.cs

How to reconfigure SQLTransport based NServicebus in Asp.net Web API?

I am using NServicebus(version 4.6.3) with SQLTransport in my ASP.net web api project. I have different connectionstrings for the queues for different environments (Dev,QA,etc). My configuration looks like below:
public class BusConfigurator
{
public static IStartableBus Bus { get; private set; }
public static void DisposeBus()
{
if (Bus == null)
return;
Bus.Shutdown();
Bus.Dispose();
Bus = null;
}
public static void InitializeServiceBus(string connectionString)
{
var configure = Configure.With()
.DefineEndpointName("MyEndPoint")
.Log4Net(new DebugAppender { Threshold = Level.Warn })
.UseTransport<SqlServer>(connectionString)
.PurgeOnStartup(false)
.SetDefaultTransactionLevel()
.UnicastBus(); // Error is thrown here on second call
configure.MyCustomSQLServerPersistence();
Bus = configure.CreateBus();
}
public static void StartBus()
{
Bus.Start(() => Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install());
}
}
I have a dropdown in the app so that the user can select the environment. Based on the selection, I want to reconfigure the bus. So, I call DisposeBus then pass the connection string to the IntializeServiceBus method followed by the startBus. It works first time but throws error below when it gets called again with different connectionstring:
Unable to set the value for key: NServiceBus.Transport.ConnectionString. The settings has been locked for modifications. Please move any configuration code earlier in the configuration pipeline
Source=NServiceBus.Core
Line=0
BareMessage=Unable to set the value for key: NServiceBus.Transport.ConnectionString. The settings has been locked for modifications. Please move any configuration code earlier in the configuration pipeline
Is NServicebus intended to be used/configured this way? (I am guessing probably not) If not then is there a workaround/different approach for this?
In V4 or below, there is no way to do it by normal human means. There is only one Bus per AppDomain. All of the configuration API is static, so if you try, you get exactly the problems you ran into.
By "human means", I mean that it might be possible to do something crazy with spinning up a new AppDomain within your process, setting up a Bus within that, and then tearing it down when you're finished. It might be possible. I haven't tried it. I wouldn't recommend it.
In V5, the configuration API is completely redesigned, is not static, and so this is possible:
var cfg = new BusConfiguration();
// Set up all the settings with the new V5 Configuration API
using (var justOneBus = NServiceBus.Bus.Create(cfg).Start())
{
// Use justOneBus, then it gets disposed when done.
}
That's right. It's disposable. Then you can do it again. In your case you wouldn't want to put it in a using block - you would want to set it up somewhere, and when the dropdown gets switched, call Dispose on the current instance and rebuild it with the new parameters.
Keep in mind, however, that the Bus is still pretty expensive to create. It's definitely still something you want to treat as an application-wide singleton (or singleton-like) instance. You definitely wouldn't want to spin up a separate one per web request.

WebService and Configuration

I created a WebService using the .NET 2.0 framework, a class based on an interface that has the WebServiceAttribute and hosting it using IIS and a ASMX file. The WebService currently loads its configuration from one XML file.
I'd like to create multiple instance of this service where each loads it own configuration.
By coping the ASMX file I can create a clone of the webservice under a different name which will be based on exact the same implementation. But it also loads the exact same configuration file which makes it rather useless.
So my question is: What is the best way to create an arbitrary number of WebServices that are based on one class, living in one IIS virtual directory where each is loading a different configuration file?
Solution
With the help of Pavel Chuchuva's answer I created the following code to handle the loading of the configuration:
public class WebConfigManager
{
public static T Load<T>() where T: new()
{
string location =
HttpContext.Current.Request.PhysicalPath + ".config";
if (HttpContext.Current.Cache[location] is T)
{
return (T)HttpContext.Current.Cache[location];
}
using (Stream s =
new FileStream(location, FileMode.Open, FileAccess.Read))
{
return (T)(HttpContext.Current.Cache[location] =
new XmlSerializer(typeof(T)).Deserialize(s));
}
}
}
// example of the usage of WebConfigManager
public class MyWebService : IMyWebService
{
Config config = WebConfigManager.Load<Config>();
...
Copy and paste .asmx file to create multiple instances of your web service (e.g. Service1.asmx, Service2.asmx and so on).
Load configuration file based on Context.Request.FilePath value:
public string LoadConfig()
{
string configPath = Server.MapPath(this.Context.Request.FilePath + ".xml");
using (XmlReader reader = XmlReader.Create(configPath))
{
// Will read Service1.asmx.xml, Service2.asmx.xml and so on
}
}
I suggest placing the asmx in different folders and placing a web.config in each of those folders with the setting for that specific instance of the web service. This is the easy and fast way
OR
you could use Web Service Enhancements 3.0 and create a WSE router, redirect a calls to a ASMX to that router and let the router forward the call to the right web service instance and pass additional config. This a more complex way of doing it but it enables u to use a single instance of the web service that's picks the right configuration based on the parameters the router passes it.
For more info on WSE3.0 I point you to the MSDN.
Hope this helps!

Categories