Q: How to extend the routing config in Rebus - rebus

I have a rebus config project which is shared for many web api projects
So basically, it looks like
Web api 1 ==> Shared Rebus Config
Web api 2 ==> Shared Rebus Config
Web api 3 ==> Shared Rebus Config
My question is, if I have some messages & handlers in Web api 3 project, how can I configure the routing for them?
My current config:
var autofacContainerAdapter = new AutofacContainerAdapter(container);
return Configure
.With(autofacContainerAdapter)
.Serialization(s => s.UseNewtonsoftJson())
.Routing(r =>
{
r.TypeBased()
.MapAssemblyOf<ProjectA.MessageA>(EnvironmentVariables.ServiceBusQueueName)
.MapAssemblyOf<ProjectB.MessageB>(EnvironmentVariables.ServiceBusQueueName);
})
.Sagas(s =>
{
s.StoreInSqlServer(EnvironmentVariables.ConnectionString, "Saga", "SagaIndex");
})
.Options(o =>
{
o.LogPipeline();
o.EnableDataBus().StoreInBlobStorage(EnvironmentVariables.AzureStorageConnectionString, EnvironmentVariables.BlobStorageContainerName);
o.EnableSagaAuditing().StoreInSqlServer(EnvironmentVariables.ConnectionString, "Snapshots");
})
.Logging(l =>
{
l.Use(new SentryLogFactory());
})
.Transport(t =>
{
t.UseAzureServiceBus(EnvironmentVariables.AzureServiceBusConnectionString, EnvironmentVariables.ServiceBusQueueName).AutomaticallyRenewPeekLock();
})
.Start();

Well... as you have probably already found out, it is not possible to make additional calls to the .Routing(r => r.TypeBased()....) part. Therefore, I can see two fairly easy ways forward:
1: Simply pass additional parameters to your shared configuration method from the outside, e.g. something like this:
var additionalEndpointMappings = new Dictionary<Assembly, string>
{
{ typeof(Whatever).Assembly, "another-queue" }
};
var bus = CreateBus("my-queue", additionalEndpointMappings);
which of course then needs to be handled appropriately in the .Routing(...) configuration callback.
2: Pull out all the common configurations into a new extension method. I almost always use this method myself, because I have found it to be easy to maintain.
First you create a new RebusConfigurer extension method in a shared lib somewhere:
// shared lib
public static class CustomRebusConfigEx
{
public static RebusConfigurer AsServer(this RebusConfigurer configurer, string inputQueueName)
{
return configurer
.Logging(...)
.Transport(...))
.Sagas(...)
.Serialization(...)
.Options(...);
}
}
and then you can call this by going
Configure.With(...)
.AsServer("my-queue")
.Start();
in your endpoints.
3: A combination of (1) and (2) which enables this:
Configure.With(...)
.AsServer("my-queue")
.StandardRouting(r => r.MapAssemblyOf<MessageType>("somewhere-else"))
.Start();
which can end up avoiding repetitive code, still preserving a great deal of flexibility, and actually looking pretty neat :)

Related

Swagger API definition load API definition - Cant use schema id "$Module"

I am getting this exception when I want to create a Domain object with name Module
InvalidOperationException: Can't use schemaId "$Module" for type "$Pro.Core.Domain.Module". The same schemaId is already used for type "$System.Reflection.Module"
Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository.RegisterType(Type type, string schemaId)
Seems like this name Module is conflicting with some System.Reflection.Module.
I have searched the internet and I have below 2 solutions that can get this working:
Rename my Module class name to something else but not Module(lets say MyModule)
Doing something like below
public void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(config =>
{
//some swagger configuration code.
//use fully qualified object names
config.CustomSchemaIds(x => x.FullName);
}
}
But I want to understand that what is there in name Module that creates this error. I don't see any reason for not being allowed to use this name as my domain class name.
Is there any way to use the Domain Object with name Module other that mentioned above in point 2 and why is this happening in the first place?
Fixed by using
services.AddSwaggerGen(options =>
{
options.CustomSchemaIds(type => type.ToString());
});
Find more details from
here

Upgrading to WebJobs SDK 3.0 has broken overridden configuration in appsettings

I migrate a WebJobs project to 3.0 and I've run into a peculiar issue. My project has an appsettings.json and various appsettings.environment.json files.
When running under any environment, instead of the environment settings overriding the base settings, the reverse is occurring: When any settings exist in the base settings and environment settings, the base settings is used.
I've tried variations of using HostBuilder.ConfigureAppConfiguration() and HostBuilder.ConfigureHostConfiguration() and in each case I notice something peculiar when I look at hostInstance.Configuration.Providers: There are always three instances of JsonConfigurationProvider, with either two inside ChainedConfigurationProvider when configuring host or just as part of the main provider array when using application. The first instance is always my base, the second is always the environment and the third is always the base again.
So I believe my problem is that this third JsonConfigurationProvider is getting added, but I don't know how it is getting added.
Here is the relevant code from my WebJob:
var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")
?? Environment.GetEnvironmentVariable("ENV")
?? "development";
var builder = new HostBuilder()
.UseEnvironment(envName)
.ConfigureAppConfiguration(b =>
{
b.SetBasePath(Environment.CurrentDirectory)
.AddCommandLine(args, StartupSettings.SwitchMapping)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{envName}.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
});
builder.ConfigureWebJobs((context, b) =>
{
b.AddAzureStorageCoreServices();
b.AddAzureStorage();
b.AddTimers();
});
builder.ConfigureLogging((context, b) =>
{
if (false && context.HostingEnvironment.IsDevelopment())
{
b.SetMinimumLevel(LogLevel.Debug);
}
else
{
b.SetMinimumLevel(LogLevel.Information);
b.AddFilter("Microsoft.EntityFrameworkCore.Database.Command", LogLevel.Warning);
}
b.AddConsole();
var applicationInsightsKey = context.Configuration.GetValue<string>("ApplicationInsights:InstrumentationKey");
b.AddApplicationInsights(o => o.InstrumentationKey = applicationInsightsKey);
})
.UseConsoleLifetime();
builder.ConfigureServices((context, services) =>
{
/*...*/
});
return builder.Build();
Just figured it out.
The extension method for ConfigureWebJobs() calls ConfigureAppConfiguration() and automatically adds appsettings. Since I was calling it after calling ConfigureAppConfiguration() that was the reason the last appsettings.json was the base one.
Code from WebJobsHostBuilderExtensions.ConfigureWebJobs:
builder.ConfigureAppConfiguration(config =>
{
config.AddJsonFile("appsettings.json", optional: true);
config.AddEnvironmentVariables();
});
The worst part is that these seems so superfluous.

Is it possible to configure everything within context?

I am trying to configure Audit.net and define my custom logic for saving logs.
Is there a way to configure included entities within context?
I tried this
`
public ResidentMasterContext(DbContextOptions options) : base(options)
{
AuditDataProvider = new DynamicDataProvider();
Mode = AuditOptionMode.OptIn;
IncludeEntityObjects = true;
EntitySettings = new Dictionary<Type, EfEntitySettings>
{
{typeof(Apartment), new EfEntitySettings()}
};
}
`
but OnScopeSaving is not firing. And when I change mode to OptOut it takes all entities
I guess you are referring to the Audit.NET EntityFramework extension.
if you use OptIn you need to mark the included entities with [AuditInclude] attribute, or use the Include methods of the fluent API. You can check the documentation here.
An example using the fluent API for the EF configuration, to include only the entities User and UserDetail:
Audit.EntityFramework.Configuration.Setup()
.ForContext<ResidentMasterContext>(config => config
.IncludeEntityObjects())
.UseOptIn()
.Include<User>()
.Include<UserDetail>();
An example of the output configuration:
Audit.Core.Configuration.Setup()
.UseDynamicProvider(_ => _.OnInsertAndReplace(auditEvent =>
{
Console.WriteLine(auditEvent.ToJson());
}));

Using Meteor authentication in configServer in call to createApolloServer

I want to add a traditional rest endpoint to my Apollo server and I would like to reuse Meteors authentication system. However, Meteor.user() is not defined in this context. The endpoint will not look or ask for user credentials.
createApolloServer( ... , {
configServer: (app) => {
app.use('/myEndpoint', () => {
/* I want to have a meteor userId here */
});
},
});
If you are using Meteor, the best way to make a traditional REST endpoint is:
https://github.com/stubailo/meteor-rest/
simple:json-routes
and you can do authentication with
simple:rest-accounts-password
simple:authenticate-user-by-token
The best way to get Meteor user information in your resolvers is:
http://dev.apollodata.com/core/meteor.html

Google OAuth in ASP.NET 5 MVC 6

I'm new to ASP.NET vNext and I don't find how to configure Google OAuth.
I have uncomment the line in Startup.cs:
app.UseGoogleAuthentication();
But where am I supposed to configure it? I tried to replicate the pattern:
services.Configure<MicrosoftAccountAuthenticationOptions>(options =>
{
options.ClientId = Configuration["Authentication:MicrosoftAccount:ClientId"];
options.ClientSecret = Configuration["Authentication:MicrosoftAccount:ClientSecret"];
});
But
services.Configure<GoogleOAuth2AuthenticationOptions>
Isn't recognized even if the dependency is present in project.json:
"Microsoft.AspNet.Authentication.Google": "1.0.0-beta5",
What am I missing?
There is a sample at https://github.com/aspnet/Security/blob/dev/samples/SocialSample/Startup.cs.
I haven't tried it, but it looks like you configure it using app.UseGoogleAuthentication():
app.UseGoogleAuthentication(options =>
{
options.ClientId = "560027070069-37ldt4kfuohhu3m495hk2j4pjp92d382.apps.googleusercontent.com";
options.ClientSecret = "n2Q-GEw9RQjzcRbU3qhfTj8f";
options.Events = new OAuthEvents()
{
OnRemoteError = ctx =>
{
ctx.Response.Redirect("/error?ErrorMessage=" + UrlEncoder.Default.Encode(ctx.Error.Message));
ctx.HandleResponse();
return Task.FromResult(0);
}
};
});
If you're using the configuration store like this
Configuration["Authentication:MicrosoftAccount:ClientId"];
then what you're also missing (if that's what you mean by 'configure Google OAuth') is the part where you store the values in the SecretManager as described in the ASP.NET docs (they use facebook but you can just put whatever keys you want in there). It's a command line tool and it avoids you storing the keys in the code like that. In Google's case you'd probably want to change it to:
Configuration["Authentication:Google:ClientID"];
Configuration["Authentication:Google:ClientSecret"];
but it can be whatever you want.

Resources