Azure Function - Failed to start a new language worker for runtime: dotnet-isolated - azure

I have a dotnet 5 function app that I've been building and deploying from a devops pipeline for a couple of weeks.
Following the most recent release, I see the following error in App Insights:
Exception type System.TimeoutException
Exception message The operation has timed out.
LogLevel Error
prop__{OriginalFormat} Failed to start a new language worker for runtime: dotnet-isolated.
Category Microsoft.Azure.WebJobs.Script.Workers.Rpc.RpcFunctionInvocationDispatcher
System.TimeoutException: The operation has timed out.
at Microsoft.Azure.WebJobs.Script.Grpc.GrpcWorkerChannel.StartWorkerProcessAsync()
csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
<UserSecretsId>4f786da6-0d47-4ccc-b343-638a6e34e1cf</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<None Remove="local.settings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.2.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Abstractions" Version="1.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage" Version="4.0.4" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.0.3" />
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.6.1" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="5.0.0" />
<PackageReference Include="NSwag.AspNetCore" Version="13.11.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.ApplicationInsights" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="5.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\infrastructure\SmsRouter.GovNotify\SmsRouter.GovNotify.csproj" />
<ProjectReference Include="..\SmsRouter.Infrastructure\SmsRouter.EntityFramework.csproj" />
<ProjectReference Include="..\SmsRouter.Utrn\SmsRouter.Utrn.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
host.json:
{
"version": "2.0"
}
Function App Configuration:
[
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "<my key is here>",
"slotSetting": true
},
{
"name": "AzureWebJobsStorage",
"value": "DefaultEndpointsProtocol=https;AccountName=storesmsroutermsdn;AccountKey=<my key is here>;EndpointSuffix=core.windows.net",
"slotSetting": false
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~3",
"slotSetting": false
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet-isolated",
"slotSetting": false
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "DefaultEndpointsProtocol=https;AccountName=storesmsroutermsdn;AccountKey=<my key is here>;EndpointSuffix=core.windows.net",
"slotSetting": false
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "func-smsrouter-msdn-01b300",
"slotSetting": false
},
{
"name": "WEBSITE_ENABLE_SYNC_UPDATE_SITE",
"value": "true",
"slotSetting": false
},
{
"name": "WEBSITE_RUN_FROM_PACKAGE",
"value": "1",
"slotSetting": false
}
]
Function Definition
[Function("HttpExample")]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString("Welcome to Azure Functions!");
return response;
}
Has anyone else run into this problem?
Note: I have now created a support ticket for this via the Azure Portal - the id is 2106280050000196. Github issue here
Edit: Following the suggestion from #Kaylan, I used Azure CLI to create a new function app with --runtime dotnet-isolated param. I then deployed my functions into this (using devops pipeline with the Deploy Azure Function task) but I'm afraid I continue to see the same error.
I've also tried deploying to a fixed app service plan (rather than consumption) but continued to hit the same problem.

I was just dealing with the same problem. I finally fixed it by adding .ConfigureFunctionsWorkerDefaults() to my Program.cs file. I had removed it by accident.
I guess what I'm saying is, make sure you have .ConfigureFunctionsWorkerDefaults() in your Program.cs file. Here's an example:
using DataApi.AzureFunctions.Throttled;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureAppConfiguration(configBuilder => configBuilder.AddEnvironmentVariables())
.ConfigureFunctionsWorkerDefaults() // <---- OMITTING THIS IS ONE POSSIBLE CAUSE OF THE ERROR "Failed to start a new language worker for runtime: dotnet-isolated."
.ConfigureServices(Startup.Configure)
.UseDefaultServiceProvider((_, options) =>
{
options.ValidateScopes = true;
options.ValidateOnBuild = true;
})
.Build();
await host.RunAsync();

I got this propblem because I'd moved form a "normal" dotnet service and needed to tweak the FUNCTIONS_WORKER_RUNTIME from dotnet to dotnet-isolated:
local.settings.json
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
....
}
}

Please make the below changes to your host.json file to include extensionBundle
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[2.*, 3.0.0)"
}
}
}
Upgrade to Microsoft.Azure.Functions.Worker version 1.3.0 or higher
Install-Package Microsoft.Azure.Functions.Worker -Version 1.3.0
Ensure that the appropriate runtime is specified while creating the Function App.
az functionapp create --consumption-plan-location westus --name <FunctionAppName> --resource-group <ResourceGroupName> --runtime dotnet-isolated --runtime-version 5.0 --functions-version 3 --storage-account <StorageAccountName>

I just ran a NuGet package update for:
Microsoft.Azure.Functions.Worker v1.3.0 → v1.4.0
Microsoft.Azure.Functions.Worker.sdk v1.0.3 → v1.0.4
This seems to have solved the problem.

Whatever you do, with Azure App Services and Function Apps, always, always, triple check you have all your Configuration Settings complete and typo-free. a missing or misspelled setting can cause start up and dependency injection problems with cryptic messages like this one. Also, if you are using staging slots, make sure they either also have all their configuration settings correct, or keep them stopped.

When you make some change that utterly destroy the app before it even starts, and have no idea what is causing this disaster.
If your function app is on Linux
I don't know, good luck? You can see logs of processes from Kudu when the app starts, which might help.
If your function app is on Windows
Open Kudu Console (Your Functions App > Advanced Tools > Go)
From the top menus, Debug Console > CMD
Navigate and open \home\LogFiles\eventlog.xml
note that the console opens at \home
Scroll to the bottom to see the latest error
If the file is huge and you have no idea which one is your error, you can delete the file, then restart the functions app. New logs will be populated.

Related

Azure Managed ID: how to convert azure function from connection string to managed id

I have an Azure function that looks like this:
[FunctionName("CreateWidgetWorkspace")]
public async Task<IActionResult> CreateWidgetWorkspace(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "widget/workspaces")] HttpRequest req,
[Queue("widgetworkspaces"), StorageAccount("WidgetStorageQueue")] ICollector<string> messageQueue,
ILogger log)
{
WorkspaceResponse response = new WorkspaceResponse();
var content = await new StreamReader(req.Body).ReadToEndAsync();
log.LogInformation($"Received following payload: {content}");
var workspaceRequest = JsonConvert.DeserializeObject<Workspace>(content);
if (workspaceRequest.name != null){
messageQueue.Add(JsonConvert.SerializeObject(workspaceRequest));
}
else {
response.status = "Error: Invalid Request";
response.requestId=null;
}
return new OkObjectResult(JsonConvert.SerializeObject(response));
}
Everythings works well - the connection string is defined in my local.settings.json file like this:
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"WidgetStorageQueue":
"DefaultEndpointsProtocol=https;AccountName=accountname;AccountKey=asdf+asdf+AStRrziLg=="
}
}
But now i've created a managed Identity and it has been assigned "Contributor" role on all resources inside the resource group.
So I need to refactor this code to no longer use the connection string in local.settings / environment variables. But to use the managed id.
Can you point me to an article or video that would put me on the right path?
I actually prefer not to Azure key vault if possible.
Thanks.
EDIT 1
I've added the 2 packages referenced in the answer. This is what I have in my csproj file:
<ItemGroup>
<PackageReference Include="Azure.Data.Tables" Version="12.4.0" />
<PackageReference Include="Azure.Storage.Queues" Version="12.10.0" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.Webjobs.Extensions.ServiceBus" Version="5.2.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage.Queues" Version="5.0.1" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.0.1" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None>
</ItemGroup>
And this is what my local.settings.json file looks like:
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "dotnet","WidgetStorageQueue__queueServiceUri":"https://mystorageaccountname.queue.core.windows.net"
},
"ConnectionStrings": {}
}
But I'm getting an error :
2022-05-05T19:30:00.774Z] Executed 'CreateWidgetWorkspace' (Failed, Id=asdf-a22b-asdf-asdf-asdf, Duration=6356ms)
[2022-05-05T19:30:00.777Z] System.Private.CoreLib: Exception while executing function: CreateWidgetWorkspace. Azure.Storage.Queues: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:asdf-8003-asdf-asdf-asdf
Time:2022-05-05T19:30:00.7494033Z
[2022-05-05T19:30:00.781Z] Status: 403 (Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.)
[2022-05-05T19:30:00.782Z] ErrorCode: AuthenticationFailed
[2022-05-05T19:30:00.784Z]
[2022-05-05T19:30:00.785Z] Additional Information:
[2022-05-05T19:30:00.788Z] AuthenticationErrorDetail: Issuer validation failed. Issuer did not match.
[2022-05-05T19:30:00.790Z]
[2022-05-05T19:30:00.791Z] Content:
[2022-05-05T19:30:00.793Z] <?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:asdf-8003-asdf-asdf-asdf
Time:2022-05-05T19:30:00.7494033Z</Message><AuthenticationErrorDetail>Issuer validation failed. Issuer did not match.</AuthenticationErrorDetail></Error>
[2022-05-05T19:30:00.795Z]
[2022-05-05T19:30:00.796Z] Headers:
[2022-05-05T19:30:00.797Z] Server: Microsoft-HTTPAPI/2.0
[2022-05-05T19:30:00.801Z] x-ms-request-id: asdf-asdf-asdf-asdf-60671b000000
[2022-05-05T19:30:00.802Z] x-ms-error-code: AuthenticationFailed
[2022-05-05T19:30:00.809Z] Date: Thu, 05 May 2022 19:29:59 GMT
[2022-05-05T19:30:00.810Z] Content-Length: 422
[2022-05-05T19:30:00.811Z] Content-Type: application/xml
[2022-05-05T19:30:00.812Z] .
Here's my Azure Resource Group:
Here's the function app - you can see I have assigned a user-assigned managed identity to it:
And here are the RBAC roles assigned my managed identity:
Questions
Based on my limited knowledge / reading, it feels like I should install Azure.Identity and create some sort of DefaultAzureCredential?
https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme#specifying-a-user-assigned-managed-identity-with-the-defaultazurecredential
EDIT 2
The changes suggested in the answer basically work. To clarify, the setting in local.setting.json that actually works is this:
"[nameofConnectioninC#Method]__serviceUri":"https://[nameOfStorageAccount].queue.core.windows.net/"
This fails when you local debug, but when you publish everything, upstream tests work.
To use Identity-based connections with Queue Storage, you will need to:
Update you application to use these Nuget Packages: Azure.Storage.Queues and Microsoft.Azure.WebJobs.Extensions.Storage.Queues.
Create an app settings called <CONNECTION_NAME_PREFIX>__serviceUri:
The data plane URI of the queue service to which you are connecting, using the HTTPS scheme.
https://<storage_account_name>.queue.core.windows.net
So in your case you need to create a setting called WidgetStorageQueue__serviceUri
Grant permission to your function app identity to access queue storage. If you just need to send message to a queue, you could use the Storage Queue Data Message Sender role.
I've created a small function app that reproduces this use case.
csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Storage.Queues" Version="12.9.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage.Queues" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.0" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
function file
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace FunctionApp1
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
[Queue("widgetworkspaces"), StorageAccount("WidgetStorageQueue")] ICollector<string> queueCollector,
ILogger log)
{
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
queueCollector.Add(requestBody);
return new OkObjectResult(requestBody);
}
}
}
settings file
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"WidgetStorageQueue__queueServiceUri": "https://<storage_account_name>.queue.core.windows.net"
}
}

Azure Functions HttpClient No such host is known on Request

I'm trying to see if an API is up but when I publish the code to Azure, the HttpClient fails to get anything because when it tries to .SendAsync(); the error message I get from Azure is "No Such Host is Known" but the code does work unaltered on my local environment.
Any idea from this what might be missing or would be the cause for the HttpClient Get to be failing?
public class ConnectionTester
{
[FunctionName("ConnectionTester")]
public static async Task Run([TimerTrigger("* */30 * * * *")] TimerInfo connectionTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", strAuth);
HttpRequestMessage newRequest = new HttpRequestMessage(HttpMethod.Get, strLink);
var response = await client.SendAsync(newRequest);
if (response.IsSuccessStatusCode)
{
log.LogInformation("Success");
}
else
{
log.LogError("Error");
}
}
}
I have followed the same code given in the question and reproduced below:
Stack: Azure Functions (.NET 6) - Timer Trigger
Function1.cs
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
namespace KrishFunctionApp1205
{
public class Function1
{
[FunctionName("Function1")]
public async Task RunAsync([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
var strLink = "https://stackoverflow.com/";
var strAuth = "Key05";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", strAuth);
HttpRequestMessage newRequest = new HttpRequestMessage(HttpMethod.Get, strLink);
var response = await client.SendAsync(newRequest);
if (response.IsSuccessStatusCode)
log.LogInformation("Okidoki");
else
log.LogError($"{response.StatusCode} {response.ReasonPhrase}: ");
}
}
}
local.settings.json:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}
host.json:
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
}
}
.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.15.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.0.1" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
Result when running locally:
Result when running in Azure:
Note: Few steps to resolve below error is:
HttpClient No such host is known on Request
It might be DNS issue, check the URI is working or not.
The requests you're trying to send to the URI being blocked by the corporate firewall or your system firewall.
Change the Port number in the Azure Functions Project and Run the function. (Refer here to know how to change the port number in Azure Functions)
Upgrade/Update the .NET Project SDK if any updates available in Visual Studio.
Check the Connection String is pointed to correct value.
For running locally and to use local storage emulator, then:
"AzureWebJobsStorage": "UseDevelopmentStorage=true"
To use Azure Storage account and run the function locally, then
"AzureWebJobsStorage": "<Azure-Storage-Account-Connection-String>"
This connecting string you can get from the Azure Portal > Storage Account > Access Keys > Connection String.

Azure 500 error on a Blazor Wasm Hosted with Authentication

I am at a complete loss here. I have a Blazor WASM Hosted running .net5 which has been deployed to Azure App Services. When there was no Database there was no problem deploying to Azure. It loaded and ran as expected. I have since installed Identity and a DBContext. Everything builds locally and runs properly with a local SQL instance.
On Azure, I have created a new SQLServer as well as a SQL database. On the SQL Database Firewall Settings i have "Allow Azure Services and resources to access this server" as well as a Rule for my client IP (not the IP for the Azure App).
For the App Service in Configuration i have a ConnectionString named DefaultConnection (same as in appsettings.json) with the same connection string as the SQLDatabase provides, source AppConfig, Type SqlAzure
I am publishing to Azure using the VS2019 Publish on the Server project (the startup project). I chose Target to be Azure -> Azure App Sevices (Windows) and my instance name. Configuration is Release, Target Framework net5.0, DeploymentMode Framework-dependent, Target runtime Portable.
The Service Dependencies is set to AzureSqlDatabase which uses the ConnectionName DefaultConnection, Username and Password are the Admin UserPassword setup for the SQL Server created on Azure and the SaveConnectionStringValue is Azure App Settings. (This auto populates the App Services Configuration ConnectionString described above.
When I click publish I see in the output that all publishes correctly:
Publish Succeeded.
Web App was published successfully http://bbqfriend.azurewebsites.net/
========== Build: 1 succeeded, 0 failed, 6 up-to-date, 0 skipped ==========
========== Publish: 1 succeeded, 0 failed, 0 skipped ==========
Installation of Web App Site extension Microsoft.AspNetCore.AzureAppServices.SiteExtension is in progress...
Restarting the Web App...
Successfully installed Web App extension Microsoft.AspNetCore.AzureAppServices.SiteExtension
Successfully restarted Web App.
However when the page launches, It shows a 500 Error.
If I go back to the Publish and Edit the settings - Database - DefaultConnection and Check the Use this Connection string at runtime selecting the connectionstring configured in the ServiceDependencies as well as the EntityFrameworkMigrations DataContext Apply This Migrations on publish. When I publish that profile it will do the migrations as well as the Seeds I have defined within the DataContext OnModelCreating override
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
#region Identity Seed
modelBuilder.ApplyConfiguration(new ApplicationUserConfiguration());
modelBuilder.ApplyConfiguration(new IdentityRoleConfiguration());
modelBuilder.ApplyConfiguration(new IdentityUserRoleConfiguration());
#endregion
//modelBuilder.ApplyConfiguration(new CountryConfiguration());
}
So I know the connection string is correct and there is a Database with the proper model and seeded data. Why am I getting a 500?!?
Here is my appsettings.json in the Server project
{
"ConnectionStrings": {
"DefaultConnection": "Server=.;Database={DatabaseName};Trusted_Connection=True;MultipleActiveResultSets=true"
},
"IdentityServer": {
"Clients": {
"XXXX.Client": {
"Profile": "IdentityServerSPA"
}
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.MSSqlServer" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.Authorization.DefaultAuthorizationService": "Warning",
"Microsoft.EntityFrameworkCore": "Warning",
"System": "Warning",
"System.Net.Http.HttpClient*": "Warning",
"IdentityServer4": "Warning",
"Serilog.AspNetCore": "Warning"
}
},
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "DefaultConnection",
"sinkOptionsSection": {
"tableName": "Logs"
},
"columnOptionsSection": {
"additionalColumns": [
{
"ColumnName": "InstanceId"
},
{
"ColumnName": "Origin"
},
{
"ColumnName": "SourceContext"
},
{
"ColumnName": "UserId"
},
{
"ColumnName": "Username"
}
],
"excludeAdditionalProperties": true
}
}
}
]
},
"AllowedHosts": "*"
}
Here is the Startup.cs for the Server project
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
//Register the Datacontext and Connection String
services.AddDbContext<DataContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
//Sets up the default Asp.net core Identity Screens - Use Identity Scaffolding to override defaults
services.AddDefaultIdentity<ApplicationUser>( options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireUppercase = true;
options.Password.RequiredUniqueChars = 0;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequiredLength = 8;
options.User.RequireUniqueEmail = true;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<DataContext>();
//Associates the User to Context with Identity
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, DataContext>( options =>
{
options.IdentityResources["openid"].UserClaims.Add(JwtClaimTypes.Role);
options.ApiResources.Single().UserClaims.Add(JwtClaimTypes.Role);
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove(JwtClaimTypes.Role);
//Adds authentication handler
services.AddAuthentication().AddIdentityServerJwt();
//Register Repositories for Dependency Injection
services.AddScoped<ICountryRepository, CountryRepository>();
services.AddControllersWithViews();
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext dataContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//AutoMigrates data
//dataContext.Database.Migrate();
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseSerilogIngestion();
app.UseSerilogRequestLogging();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
Here is the Program.cs for the Server project
public class Program
{
public static void Main(string[] args)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.Enrich.WithProperty("InstanceId", Guid.NewGuid())
.Enrich.WithProperty("Origin", "Server")
.CreateLogger();
try
{
Log.Information("Starting up");
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application start-up failed");
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Here is the Program.cs for the Client project
public static async Task Main(string[] args)
{
//Serilog
var levelSwitch = new LoggingLevelSwitch();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(levelSwitch)
.Enrich.WithProperty("InstanceId", Guid.NewGuid())
.Enrich.FromLogContext()
.WriteTo.BrowserHttp(controlLevelSwitch: levelSwitch)
.CreateLogger();
Log.ForContext<Program>().Information("Client has started");
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddLogging(logging =>
{
logging.ClearProviders();
logging.AddSerilog(dispose: true);
});
builder.Services.AddHttpClient("XXX.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddTransient(sp =>
sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("XXXX.ServerAPI"));
builder.Services.AddApiAuthorization()
.AddAccountClaimsPrincipalFactory<RolesClaimsPrincipalFactory>();
//Register Services
var baseAddress = new Uri($"{builder.HostEnvironment.BaseAddress}api/");
void RegisterTypedClient<TClient, TImplementation>(Uri apiBaseUrl)
where TClient : class where TImplementation : class, TClient
{
builder.Services.AddHttpClient<TClient, TImplementation>(client => client.BaseAddress = apiBaseUrl)
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
}
RegisterTypedClient<ICountryService, CountryService>(baseAddress);
await builder.Build().RunAsync();
}
I do have Serilog configured and it looks to be working as well. Here are the error messages I am seeing during the Server Launch
System.InvalidOperationException: Startup assembly Microsoft.ApplicationInsights.StartupBootstrapper failed to execute. See the inner exception for more details.
---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.ApplicationInsights.StartupBootstrapper, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
File name: 'Microsoft.ApplicationInsights.StartupBootstrapper, Culture=neutral, PublicKeyToken=null'
at System.Reflection.RuntimeAssembly.InternalLoad(ObjectHandleOnStack assemblyName, ObjectHandleOnStack requestingAssembly, StackCrawlMarkHandle stackMark, Boolean throwOnFileNotFound, ObjectHandleOnStack assemblyLoadContext, ObjectHandleOnStack retAssembly)
at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, RuntimeAssembly requestingAssembly, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, AssemblyLoadContext assemblyLoadContext)
at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.ExecuteHostingStartups()
--- End of inner exception stack trace ---
and
System.InvalidOperationException: Startup assembly DiagnosticServices.HostingStartup failed to execute. See the inner exception for more details.
---> System.IO.FileNotFoundException: Could not load file or assembly 'DiagnosticServices.HostingStartup, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
File name: 'DiagnosticServices.HostingStartup, Culture=neutral, PublicKeyToken=null'
at System.Reflection.RuntimeAssembly.InternalLoad(ObjectHandleOnStack assemblyName, ObjectHandleOnStack requestingAssembly, StackCrawlMarkHandle stackMark, Boolean throwOnFileNotFound, ObjectHandleOnStack assemblyLoadContext, ObjectHandleOnStack retAssembly)
at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, RuntimeAssembly requestingAssembly, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, AssemblyLoadContext assemblyLoadContext)
at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.ExecuteHostingStartups()
--- End of inner exception stack trace ---
UPDATE
I am able to replicate the above error messages and they are logged into the Database via Serilog.
So we can see the "Starting up" from the Server Program.cs Main method (above) and the next entry is from the EntityFramework Model Validation. Then comes the errors. I can see the Namespace as Microsoft.AspNetCore.Hosting.Diagnostics as the source of the exception.
I attempted to add a Nuget reference but that did nothing
I attempted to add a reference to added services.AddApplicationInsightsTelemetry(); to the Server Startup.cs ConfigureServices and the ApplicationInsights InstrumentationKey to the appsettings.json (which already existed within Azure as a Variable) but that did nothing
I added a reference to and added
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>().UseAzureAppServices();
});
as per a workaround found here https://github.com/dotnet/extensions/issues/2566 which did not help
Update Day 2
Adding more information as I am still getting the same exceptions. Im curious if this is a compatibility issue between versions. My application is .net5 and running on Azure using .net5 early access.
Here are my Nuget packages for the Server Project
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="5.0.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="5.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.AspNetCore.Ingestion" Version="1.0.0-dev-00012" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="5.6.0" />
</ItemGroup>
Here are the Nuget Packages for the Client project
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" />
<PackageReference Include="Serilog.Sinks.BrowserHttp" Version="1.0.0-dev-00012" />
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
</ItemGroup>
I have tried removing Serilog from both the Client and Server projects. I still received a 500.
With Serilog Removed I tried using .UseAzureAppServices() from https://github.com/dotnet/extensions/issues/2566 with no luck as well.
I did notice an additional error messsage
2021-01-06 19:00:38.322 +00:00 [Error] Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware: An unhandled exception has occurred while executing the request.
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.Extensions.DependencyInjection.IdentityServerBuilderConfigurationExtensions.<>c.<AddSigningCredentials>b__10_2(IServiceProvider sp)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
at ... (removed for post size)
I have been able to isolate this to becoming an issue when I deployed my site as a Blazor WebAssembly Hosted solution. I was able to get a version of my site which was upgraded to .net5 PRE switching from Blazor WebAssembly to Blazor WebAssembly Hosted. The .net5 version was able to be deployed to Azure without issues. When deploying the WebAssembly Hosted version is when I got 500 Errors. So this has to do with deploying a Blazor WebAssembly Hosted solution to Azure.
I also experimented by creating an out of the box Blazor WebAssembly Hosted solution without Authentication and deployed it to Azure. This works with no issues. HOWEVER, when I create an out of the box Blazor WebAssembly Hosted WITH Authentication (individual user accounts stored in app) and deployed it to Azure it fails with 500!
The easiest way to make it work:
Add/set the env variable ASPNETCORE_ENVIRONMENT to Development
...and your Hosted Blazor WASM with Identity will finally work in Azure App Service
If you don't want the easy way above, do these instead:
Generate a self-signed certificated by following this article:
(in the Generating a Self-Signed Certificate section)
https://gavilan.blog/2020/08/18/blazor-using-a-self-signed-certificate-for-identityserver4-in-azure-app-service/
Remember the password you used for the generated certificate.
Place the certificate in your project (e.g. in the server project)
Append these in the appsettings.json file:
Publish the app once again.

No data in application-insights when deployed on Azure

I have a .net core 2 MVC web application that uses application insights on Azure.
I also configured nlog to trace with application insights.
Everything works on my pc, as I found exceptions and tracing on azure, but when I deploy the application and use it on azure it doesn't generates any event on application insights (I found only the events in the log file).
So I tried to create an instance of TelemetryClient in a controller and it works even in the the deployed instance:
TelemetryClient tc = new TelemetryClient()
{
InstrumentationKey = "11111111-2222-3333-4444-555555555555"
};
tc.Context.User.Id = Environment.MachineName;
tc.Context.Session.Id = "session_id";
tc.Context.Device.OperatingSystem = Environment.OSVersion.ToString();
tc.TrackTrace("Privacy page says hello with TelemetryClient");
Here are the snippets of my project:
appsettings.json
{
"ApplicationInsights": {
"InstrumentationKey": "11111111-2222-3333-4444-555555555555"
}
}
appsettings.Staging.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=tcp:dom.database.windows.net,1433;Initial Catalog=dom;Persist Security Info=False;User ID=user;Password=pass;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
},
"AllowedHosts": "*",
"Logging": {
"LogLevel": {
"Default": "Trace",
"System": "Information",
"Microsoft": "Information"
}
}
}
I defined the same ASPNETCORE_ENVIRONMENT value on my VS and on Azure (Staging) to be sure to load the same appsettings and deployed all the files.
I load the configuration in this way
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{environmentName}.json", optional: true)
.AddEnvironmentVariables()
.Build();
CreateWebHostBuilder is this
public static IWebHostBuilder CreateWebHostBuilder(string[] args, IConfiguration config) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext) =>
{
//config.AddJsonFile("appsettings.json");
})
.UseStartup<Startup>()
.ConfigureLogging(
logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
})
.UseApplicationInsights() // Enable Application Insights
.UseNLog();
nlog.config contains
<extensions>
<add assembly="Microsoft.ApplicationInsights.NLogTarget" />
</extensions>
<targets>
<target type="ApplicationInsightsTarget" name="aiTarget" />
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
layout="${longdate} ${uppercase:${level}} ${message}" />
</targets>
<rules>
<logger name="*" minlevel="Warn" writeTo="aiTarget" />
<logger name="*" minlevel="Warn" writeTo="f" />
</rules>
It seems to me that something is wrong in the configuration or the InstrumentationKey, but I don't know how to inspect it.
Any idea, or... is there any way to know how the application insights library is configured in order to find some useful info to solve the problem? I tried with the remote debugging but I have no idea of what inspect.
Based on your description, I think you have set another application insights key in azure portal -> your web application -> configuration-> application settings.
Please check if you did this or not:
If the key is there, you need remove it. Or put this line of code AddEnvironmentVariables() before the AddJsonFile(), like below:
var configuration = new ConfigurationBuilder()
.AddEnvironmentVariables() //put this before AddJsonFile()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{environmentName}.json", optional: true)
.Build();
Please let me know if you have more issues.

Azure functions function.json generates with incorrect scriptFile path

I've finally managed to get my function.json file to generate with mostly the correct attributes. The only problem I'm still struggling with is that the scriptFile path if set to the wrong value.
It gets generated with a value of "bin/MyFunctions.dll" instead of "../bin/MyFunctions.dll". This happens whether I build or publish.
When I try and run the script host I get the error:
The following 1 functions are in error:
Echo: Invalid script file name configuration. The 'scriptFile' property is set to a file that does not exist.
Manually changing the value to "../bin/MyFunctions.dll" solves the issue.
csproj file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<NoWarn>NU1701</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.0.0" />
<PackageReference Include="Microsoft.Azure.WebJobs" Version="3.0.0-beta3" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.6" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
EchoFunction.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs.Host;
using System.Linq;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
namespace EchoFunctionNameSpace
{
public class EchoFunction
{
[FunctionName("Echo")]
public static IActionResult Run(
[HttpTriggerAttribute(AuthorizationLevel.Anonymous, "get", Route = "name/{name}/sname/{sname}")]
HttpRequest req, TraceWriter log, string name, string sname)
{
log.Info("C# HTTP trigger function processed a request.");
return new OkObjectResult($"Hello {name} {sname}");
}
}
}
host.json
{}
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"AzureWebJobsDashboard": ""
}
}
Those are the only 4 files I have. dotnet build/publish produces a file Echo/function.json that looks like this:
{
"generatedBy": "Microsoft.NET.Sdk.Functions.Generator-1.0.6",
"configurationSource": "attributes",
"bindings": [
{
"type": "httpTrigger",
"route": "name/{name}/sname/{sname}",
"methods": [
"get"
],
"authLevel": "anonymous",
"name": "req"
}
],
"disabled": false,
"scriptFile": "bin/AzureFunctions.dll",
"entryPoint": "EchoFunctionNameSpace.EchoFunction.Run"
}
I found what I believe to be a bug in the SDK functions generator code. I have submitted a pull request here to try and get it resolved:
https://github.com/Azure/azure-functions-vs-build-sdk/pull/143

Resources