I have an Azure Functions (.NET Core) project and I would like to select an implementation for some class depending on the environment. Something like the following:
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddLogging();
#if azure environment
builder.Services.AddSingleton<IAzureApi, AzureApi>();
#else
builder.Services.AddSingleton<IAzureApi, AzureApiStub>();
#endif
}
}
What would be the best way to do this? Is it possible to configure such behavior local.settings.json?
Easy way to achieve this by using custom property in the config file.
[FunctionName("CustomSettings")]
public static Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "GET")]HttpRequestMessage req, TraceWriter log)
{
var customSetting = Environment.GetEnvironmentVariable("AzureEnvironment", EnvironmentVariableTarget.Process);
if(customSetting == "Development")
{
//dosomething
}
}
Add this property in the azure portal manually (AppSettings).
for more info -> https://learn.microsoft.com/en-us/sandbox/functions-recipes/environment-variables?tabs=csharp
https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library#environment-variables
You could use the DEBUG preprocessor directive in your Startup.cs file:
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
#if DEBUG
builder.Services.AddSingleton<IAzureApi, AzureApiStub>();
#else
builder.Services.AddSingleton<IAzureApi, AzureApi>();
#endif
}
}
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives/preprocessor-if
You have to be running your solution in Debug configuration which I assume you would be doing when running locally?
Related
I'm working on a solution that interacts with Redis, using the servicestack.net library.
I have a class that inherits from ServiceStack.AppHostBase and asks me for an override of the Configure method. This method has as a parameter a Funq.Container that I see is an implementation of IServiceProvider, IResolver and IContainer, and none of these interfaces have the AddHttpClient method that is provided by the IServiceCollection. Method I need to be able to inject the IHttpClientFactory. Any idea how to solve my problem?
To do it in ASP.NET (not .NET Core), the quick way would be to:
install Microsoft.Extensions.DependencyInjection package and call .AppHttpClient() extension
Build the Service Provider you would normally see in .NET Core
Get the instance of IHttpClientFactory from the Service Provider
Register the instance of IHttpClientFactory with Funq.Container again
using Microsoft.Extensions.DependencyInjection;
public class AppHost : AppHostBase
{
public override void Configure(Container container)
{
...
RegisterHttpClientFactory(container);
}
private container RegisterHttpClientFactory(Container container)
{
var services = new ServiceCollection()
.AddHttpClient();
// You can kind of inspect services returned.
// You can see this extension registers lot of other things too beside
// IHttpClientFactory.
// Also you can see the lifetime of IHttpClientFactory is Singleton.
var serviceProvider = services.BuildServiceProvider();
container.AddSingleton(serviceProvider.GetService<IHttpClientFactory>());
return container;
}
}
If you happen to use Unity Adaptor
Unity has a package to give you an extension as well to build the Service Provider directly into the Unity Container:
using Microsoft.Extensions.DependencyInjection;
using Unity;
using Unity.Microsoft.DependencyInjection;
public static class UnityConfig
{
public static void RegisterTypes(IUnityContainer container)
{
...
container.RegisterServices();
container.RegisterHttpClientFactory();
}
private static IUnityContainer RegisterHttpClientFactory(
this IUnityContainer unityContainer)
{
new ServiceCollection()
.AddHttpClient()
.BuildServiceProvider(unityContainer);
return unityContainer;
}
}
This is the interface definition of IServiceCollection from IServiceCollection.cs:
public interface IServiceCollection : IList<ServiceDescriptor>
{
}
AddHttpClient is just an extension method from Microsoft.Extensions.DependencyInjection that wraps adding a number of additional dependencies to ASP.NET Core IOC.
So you should continue to register it on ASP.NET Core IOC, i.e:
public class Startup : ModularStartup
{
public new void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseServiceStack(new AppHost
{
AppSettings = new NetCoreAppSettings(Configuration)
});
}
}
As any dependencies registered .NET Core Startup are also available to ServiceStack.
My Azure function doesn't calls the startup class localy.
When running the project, my brekpoint doesn't hit the DependencyRegistrations.Register function.
Package Microsoft.Azure.Functions.Extensions is correctly installed
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
DependencyRegistrations.Register(builder.Services);
}
}
}
Why is the startup class not called?
Two things I'm not seeing in your code snippet.
1- [assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
2- Are you sure the nuget package was properly installed? (Microsoft.Azure.Functions.Extensions)
The final startup code should look like the following:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient();
builder.Services.AddSingleton<IMyService>((s) => {
return new MyService();
});
builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
}
}
}
Just in case you're running v4, Startup is not used.
Perform the dependency injection setup in Program.cs:
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(builder =>
{
builder.AddTransient<IUserService, UserService>();
builder.AddTransient<ICompetitionService, CompetitionService>();
builder.AddTransient<ICompetitionRepository, CompetitionRepository>();
})
.Build();
host.Run();
I face the same issue, i have to remove my project from my solution and recreate an new to have the statup to be called...
I suspect a version mistake somewhere
I use asp.net core logging like this:
public class MyClass
{
private readonly ILogger<MyClass> _logger;
public readonly EventId NoEntryFoundEventId = new EventId(1, "No Entry Found");
public MyClass(ILogger<MyClass> logger)
{
_logger = logger;
}
public void Foo(decimal entryId)
{
_logger.LogError(NoEntryFoundEventId, "MyCustomMessage\t: Entry ID: {EntryId}", entryId);
}
}
An I setup the logger like this:
services.AddApplicationInsightsTelemetry();
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Information)
How do I find the logs for MyClass in Azure portal?
As far as I understand, you want to find the log entries in Application Insights that are specifically linked to your class MyClass.
It is in the Property "CategoryName".
Getting Started with Application Insights for ASP.NET Core
Your program.cs should look something like this
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
Then link the ASP.NET ILogger to Application Insights
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
/*...existing code..*/
loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Warning);
}
If you set it up like this, your ILogger will automatically use the full name of MyClass as a category name, and you will see that in Application Insights under the property "CategoryName".
https://github.com/Microsoft/ApplicationInsights-aspnetcore/tree/develop/src/Microsoft.ApplicationInsights.AspNetCore/Logging/Implementation
private void PopulateTelemetry(ITelemetry telemetry,
IReadOnlyList<KeyValuePair<string, object>> stateDictionary, EventId eventId)
{
IDictionary<string, string> dict = telemetry.Context.Properties;
dict["CategoryName"] = this.categoryName;
...
See also this question for an image on how this will look in Application Insights:
Using Application Insights with ILoggerFactory
(Image is taken directly from this answer, please tell me if this is not allowed and I will remove it)
The data is added as a "custom property" and can be filtered like that in the portal:
Some more info:
https://learn.microsoft.com/en-us/azure/application-insights/app-insights-api-custom-events-metrics#properties
https://learn.microsoft.com/en-us/azure/application-insights/app-insights-analytics-tour#custom-properties-and-measurements
I have an OWIN pipeline using Nancy:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseNancy();
}
}
The UseNancy() is actually a call to my own custom extension method defined in this gist: https://gist.github.com/TheFastCat/0b7635d9e5795b44e72e
This code is executed both as an Azure Website or an Azure Cloud Service. Based on the context it is executing within I want to use a particular favicon, loaded as an embedded resource from a separate assembly. I do this by specifying separate NancyBootstrappers (each loading the proper favicon for its context).
Is there a more elegant solution to determining the runtime application that is executing the OWIN pipeline? Currently I check app.Properties["host.AppName"] ; however while the Website's app name matches it's assembly configuration, the CloudService app is the name of the Owin startup assembly.class. (see gist). It's cloogey.
Is there a more elegant/simple solution for specifying a custom favicon within Nancy for each of my web applications than creating separate bootstrappers and doing runtime application context checks?
I solved this problem with the help of others on the https://jabbr.net/#/rooms/owin and https://jabbr.net/#/rooms/nancyfx chat boards
Yes. You can contextually check the OWIN host properties:
if (app.Properties.ContainsKey("System.Net.HttpListener"))
{
// self hosted application context
}
2.) Yes.
namespace ClassLib
{
public class Startup()
{
public Startup(byte[] favIcon) { ... }
public void Configuration(IAppBuilder app) { ... }
}
}
[assembly: OwinStartup(typeof(WebHost.Startup))]
namespace WebHost
{
public class Startup()
{
public voic Configuration(IAppBuilder app)
{
new ClassLib.Startup(webhostFavIcon).Configuration(app);
}
}
}
namespace SelfHost
{
private class Program()
{
public void Main(string[] args)
{
using(WebApp.Start(app => new ClassLib.Startup(selfHostFavIcon).Configuration(app))
{}
}
}
}
I have this simple self hosted "Hello World" app which I doesn't understand how it works 100 %.
namespace HelloOwin
{
using System;
using Microsoft.Owin.Hosting;
using Owin;
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;
class Program
{
static void Main(string[] args)
{
using(WebApp.Start<Startup>(url: "http://localhost:9765/"))
{
Console.ReadLine();
}
}
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Run(context =>
{
var task = context.Response.WriteAsync("Hello world!");
return task;
});
}
}
}
For each request I'm doing to this application the Func defined in app.Run is run twice, why so?
Preinitialization calls means just some code that you want to be executed before you call configureapp in the startup. you can do some operation that requires this or some logging really depends on your requirements.