I am trying to use NancyFX (clint-eastwood) with dotnetcore1.1 and dotnet-cli 1.0.0-rc4-004771. My current project structure is -
CustomBootstrapper.cs
HomeModule.cs
index.sshtml
nancyapp.csproj
Program.cs
Startup.cs
And codes are -
nancyapp.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Owin">
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel">
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="Nancy">
<Version>2.0.0-clinteastwood</Version>
</PackageReference>
</ItemGroup>
</Project>
Program.cs
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
namespace nancyapp
{
class Program
{
static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
Startup.cs
using Microsoft.AspNetCore.Builder;
using Nancy.Owin;
namespace nancyapp
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseOwin(x => x.UseNancy());
}
}
}
HomeModule.cs
using Nancy;
namespace nancyapp
{
public class HomeModule : NancyModule
{
public HomeModule()
{
Get("/", _ => { return View["index.sshtml"]; });
Get("/test/{name}", args => new Person() { Name = args.name });
}
}
public class Person
{
public string Name { get; set; }
}
}
index.sshtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
Welcome to Nancy App.
</body>
</html>
CustomBootstrapper.cs is currently empty.
When I try to access Get("/test/{name}", args => new Person() { Name = args.name }); from a rest client i get the expected result.
However, when I try to access to root or Get("/", _ => { return View["index.sshtml"]; });, I get a 500 server error saying -
Error details are currently disabled. To enable it, please set
TraceConfiguration.DisplayErrorTraces to true. For example by
overriding your Bootstrapper's Configure method and calling
environment.Tracing(enabled: false, displayErrorTraces: true)
I tried following the instruction in the error message and enable error tracing by including the following code in CustomBootstrapper.cs
protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, IPipelines pipelines)
{
var environment = GetEnvironment();
environment.Tracing(true, true);
}
But then I get the following error when trying to run the application with dotnet run
Unhandled Exception: System.ArgumentException: An item with the same
key has already been added. Key: Nancy.TraceConfiguration at
System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(Object key) at
System.Collections.Generic.Dictionary`2.Insert(TKey key,TValue value, Boolean add) at
nancyapp.CustomBootstrapper.ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) in D:\TempWork\nancyapp\CustomBootstrapper.cs:line 17 at
Nancy.Bootstrapper.NancyBootstrapperBase`1.Initialise() at
Nancy.Owin.NancyMiddleware.UseNancy(NancyOptions options) at
Nancy.Owin.DelegateExtensions.UseNancy(Action`1 builder, NancyOptionsoptions) at
nancyapp.Startup.<>c.<Configure>b__0_0(Action`1 x) in D:\TempWork\nancyapp\Startup.cs:line 10 at
Microsoft.AspNetCore.Builder.OwinExtensions.UseOwin(IApplicationBuilder builder, Action`1 pipeline) at
nancyapp.Startup.Configure(IApplicationBuilder app) in D:\TempWork\nancyapp\Startup.cs:line 10
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at
Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder app) at
Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication() at
Microsoft.AspNetCore.Hosting.WebHostBuilder.Build() at
nancyapp.Program.Main(String[] args) in D:\TempWork\nancyapp\Program.cs:line 11
I am not sure what's causing the error or how to enable tracing. Can anyone help?
The are two problems here :
The 500 is because the view was not found , what you need to do is provide a root path by implementing IRootPathProvider and return Directory.GetCurrent().
Secondly to enable tracing you need public override void Configure(INancyEnvironment environment) this adds the keys hence you the exception you are getting.
You may get the same server error (500) when using Nancy in a .NET Core 3.1 app in combination with Owin >= v3.
I've solved the issue by downgrading Microsoft.AspNetCore.Owin from v3.x to v2.2.0.
My running setup was the following after the downgrade:
It's also fine to return a simple text for testing:
Get("/", _ => { return new TextResponse(HttpStatusCode.OK, "Hello world!"); });
Related
When running test from command line (dotnet test) in a .net 5.0 project using xunit all tests seems to pass but the process crashes with the following message from the detailed verbosity of dotnet test:
Catastrophic failure: System.ArgumentException : There is at least one object in this array that cannot be serialized (Parameter 'array')
[xUnit.net 00:00:03.74] [FATAL ERROR] System.ArgumentException
[xUnit.net 00:00:03.74] System.ArgumentException : There is at least one object in this array that cannot be serialized (Parameter 'array')
[xUnit.net 00:00:03.74] Stack Trace:
[xUnit.net 00:00:03.74] C:\Dev\xunit\xunit\src\xunit.runner.utility\Extensions\MessageSinkMessageExtensions.cs(44,0): at MessageSinkMessageExtensions.Dispatch[TMessage](IMessageSinkMessage message, HashSet`1 messageTypes, MessageHandler`1 callback)
This just happened when running dotnet test from the command line, running the test from VisualStudio works.
I'm testing a dotnet 5 rest API using TestServer.
Any ideas what could be the cause?
Packages version used:
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="5.0.8" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
-- UPDATE --
I just realize that the error described here is happening when using an xUnit Theory that take the following example class as argument:
public record TruncatedString
{
public TruncatedString(string value)
{
Value = FormatTruncatedString(value);
}
protected string Value { get; }
protected static string FormatTruncatedString(string value)
{
return value.Substring(0,4);
}
public static implicit operator string(TruncatedString truncated) => truncated.Value;
public static implicit operator TruncatedString(string text) => new (text);
public override string ToString() => Value;
}
And is used in a xUnit Theory like this:
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData("ABC")]
public async Task ThestWithTheErrorMessage(TruncatedString value)
{
// ...
// THIS TEST PRODUCE THE SERIALIZATION ERROR
// System.ArgumentException : There is at least one object in this array that cannot be serialized (Parameter 'array')
// Stack Trace:
// C:\Dev\xunit\xunit\src\xunit.runner.utility\Extensions\MessageSinkMessageExtensions.cs(39,0): at MessageSinkMessageExtensions.Dispatch[TMessage](IMessageSinkMessage message, HashSet`1 messageTypes, MessageHandler`1 callback)
}
I've run into the same issue. It seems that xUnit will not run the theory test if there's an implicit conversion happening.
Rewrite your test to be like:
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData("ABC")]
public async Task Test(string input)
{
TruncatedString value = input;
// ...
}
This bug in xUnit is documented here: https://github.com/xunit/xunit/issues/1742
As a workaround for unit tests. I have added a support of IXunitSerializable to help XUnit to build the correct test case data.
public sealed record CountryCode(string Value) : IXunitSerializable
{
// It's required by IXunitSerializable
public CountryCode(): this(string.Empty) { }
public override string ToString()
{
return Value;
}
public static implicit operator CountryCode(string self)
{
return new CountryCode(self);
}
public static implicit operator string(CountryCode self)
{
return self.Value;
}
void IXunitSerializable.Serialize(IXunitSerializationInfo info)
{
info.AddValue(nameof(Value), Value, typeof(string));
}
void IXunitSerializable.Deserialize(IXunitSerializationInfo info)
{
throw new NotSupportedException("This should not be used.");
}
}
I'm trying to enhance RequestTelemetry in AppInsights from HttpTrigger Azure Function v3.
Function is initialized with DI and Startup class.
[assembly: FunctionsStartup(typeof(Startup))]
namespace Hager.Example.FunctionApp.FunctionApp
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
// No service for repro
}
}
}
And my Function
public class Function1
{
private readonly ILogger _logger;
public Function1(ILogger<Function1> logger)
{
_logger = logger;
}
[FunctionName("HttpTriggered")]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestMessage req)
{
using var loggerScope = _logger.BeginScope("{InScope1}{InScope2}{InScope3}", Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid());
_logger.LogInformation("Started Execution");
_logger.LogWarning("With a custom property: {CustomProperty}.", Guid.NewGuid());
Activity.Current?.AddTag("TagStart", Guid.NewGuid());
if (Activity.Current == null)
{
// Always null
_logger.LogError("No ActivityCurrent {Activity}.", Activity.Current);
_logger.LogError("ActivityCurrent Tags {Activity}.", Activity.Current?.Tags);
}
// Activity.Current.AddTag("Tag2", Guid.NewGuid()); // <- NullException
_logger.LogInformation("Finished Execution");
return new NoContentResult();
}
}
My project packages:
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.17.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.17.0" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.11" />
</ItemGroup>
Every logger and scopes are working as expected, but object ActivityTag is always null that shouldnt in Azure Functions.
Did I miss something?
Update:
Added Op's solution: by using request.HttpContext?.Features.Get<RequestTelemetry>(), it worked fine.
Please uninstall the 2 Application Insights packages: Microsoft.ApplicationInsights and Microsoft.ApplicationInsights.AspNetCore.
By default, Application Insights packages do not collect activity tags. So this should be the reason.
I tested your azure function without installing the above 2 Application Insights packages, it works well. Here is the screenshot of the test result:
Adding my local.settings.json here for your reference, the code is the same as yours:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "xxxx",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"APPINSIGHTS_INSTRUMENTATIONKEY": "xxx"
}
}
And if the 2 packages are necessary, maybe you can try add a custom ITelemetryInitializer by following this answer(btw, I didn't test it).
I have a .net core console application I am going to deploy as an Azure web job. The purpose of the job is to listen for new messages in an Azure Service Bus Queue. I have set the listener up using a function containing the [ServiceBusTrigger] Attribute. I built a dummy implementation which just reads the latest message from the queue - this works without issue - the message is passed correctly from the service bus queue to my function.
When I try to go to the next level and add an interface parameter to the function to be injected by DI I get an error.
Microsoft.Azure.WebJobs.Host.Indexers.FunctionIndexingException:
'Error indexing method 'Functions.ProcessMeasurementData''
InvalidOperationException: Cannot bind parameter 'service' to type
IProcessMeasurementService. Make sure the parameter Type is supported
by the binding. If you're using binding extensions (e.g. Azure
Storage, ServiceBus, Timers, etc.) make sure you've called the
registration method for the extension(s) in your startup code (e.g.
builder.AddAzureStorage(), builder.AddServiceBus(),
builder.AddTimers(), etc.).
This is my function. If I remove the parameter IProcessMeasurementService service it works with no issue running locally from Visual Studio 2019 (I haven't tried deploying to azure yet as a webjob), picking up new items as they are added to the Azure Service Bus Queue.
public class Functions
{
public static async Task ProcessMeasurementData(
[ServiceBusTrigger("process-measurement-data-queue", Connection = "AzureWebJobsServiceBus")] Message message,
IProcessMeasurementService service)
{
try
{
var measurements = JsonConvert
.DeserializeObject<List<CreateMeasurementInput>>
(Encoding.UTF8.GetString(message.Body));
await service.DoStuff(measurements);
// log.LogInformation(message.ContentType);
}
catch (Exception e)
{
throw;
}
}
I think I am registering the service correctly, like this:
{
// Register application services
services.AddSingleton<IProcessMeasurementService, ProcessMeasurementService>();
});
This is my main function in its entirety.
static void Main(string[] args)
{
var builder = new HostBuilder();
builder.ConfigureAppConfiguration((builder) =>
{
builder
.AddJsonFile("appsettings.json", false, true)
.AddEnvironmentVariables();
});
builder.ConfigureWebJobs(b =>
{
b.AddServiceBus(x =>
{
x.MessageHandlerOptions = new MessageHandlerOptions(ExceptionReceivedHandler)
{
AutoComplete = false
};
});
b.AddAzureStorageCoreServices();
});
builder.ConfigureServices(services =>
{
services.AddOptions();
// Register application services
services.AddSingleton<IProcessMeasurementService, ProcessMeasurementService>();
});
var host = builder.Build();
using (host)
{
host.Run();
}
}
From googling it feels like the problem might be something to do with my nuget package version. I tried adding a file called "host.json" in case it was a known problem with azure function versions conflicting with extensions libraries. But it did nothing. I am not actually using AzureFunctions (serverless functions I mean) but I am clutching at straws at this stage.
Does anyone know what the problem is?
This is the host.json just in case this is the issue.
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
Here're my nuget versions installed
<PackageReference Include="Microsoft.Azure.ServiceBus" Version="4.1.2" />
<PackageReference Include="Microsoft.Azure.WebJobs" Version="3.0.16" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.ServiceBus" Version="4.1.1" />
<PackageReference Include="Microsoft.Azure.WebJobs.Sources" Version="3.0.16" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" />
Change from static function method to an instance member and inject the service via constructor injection directly into the function class.
public class Functions {
private readonly IProcessMeasurementService service;
public Functions (IProcessMeasurementService service) {
this.service = service;
}
public async Task ProcessMeasurementData(
[ServiceBusTrigger("process-measurement-data-queue", Connection = "AzureWebJobsServiceBus")] Message message)
{
try {
var measurements = JsonConvert
.DeserializeObject<List<CreateMeasurementInput>>
(Encoding.UTF8.GetString(message.Body));
await service.DoStuff(measurements);
// log.LogInformation(message.ContentType);
} catch (Exception e) {
//...
throw;
}
}
}
What is the correct way to set up NLog logging for a .NET Core console application?
I see there is mention in Wiring and injected NLog into a .Net Core console application of using Microsoft.Extensions.Logging.ILogger somehow but no example and I'm having the same issue of getting a null. I tried the other examples in the posting but same thing, null object.
As an update, I got the code below to work by adding using statements for NLog.Config and then using the LogManager.GetCurrentClassLogger. I saw this in another post but I'm not sure why it works or if it's the correct way. So, I am still hoping someone can enlighten me on the correct way to get NLog setup in .NET Core or if this is the correct way, please let me know.
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Config;
using NLog.Extensions.Logging;
static void Main(string[] args)
{
var logger = LogManager.GetCurrentClassLogger();
//service collection are were we register our services
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
serviceCollection.AddLogging();
//service provider is where we get our services
serviceProvider = serviceCollection.BuildServiceProvider();
//logging (ILoggerFactory requires Microsoft.Extensions.Logging dependency and adding a using statement)
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
//NLog.LogManager.LoadConfiguration("NLog.config");
//AddNLog required adding dependency NLog.Extensions.Logging and then adding a using statement
loggerFactory.AddNLog().ConfigureNLog("NLog.config");
logger.Debug("I successfully logged a debug via NLog!");
}
The best and most recent way to add and use NLog with support for ASP.Net Core 5 is described on github
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using NLog.Web;
namespace ASP.NET_Core_5_NLog_Example
{
public class Program
{
public static void Main(string[] args)
{
var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
try
{
logger.Debug("init main");
CreateHostBuilder(args).Build().Run();
}
catch (Exception exception)
{
//NLog: catch setup errors
logger.Error(exception, "Stopped program because of exception");
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
})
.UseNLog(); // NLog: Setup NLog for Dependency injection
}
}
I have my connection string to SQL stored in the Web project in appsettings.json
"ConnectionStrings": {
"MyDbConnectionString": "***"
},
Then I added a DB context using Scaffold
Scaffold-DbContext -Connection "name=MyDbConnectionString" -Provider "Microsoft.EntityFrameworkCore.SqlServer" ... -Force
I can use the context in a controller and I have no issues getting data or writing. However, I would like all my business logic to be on a separate class library. So here is my repository from my Library:
public class MyRepository
{
private static MyContext CurrentContext
{
get { return new MyContext(); }
}
public static async void AddEventLog(EventLog eventLog)
{
using (var context = CurrentContext)
{
context.EventLog.Add(eventLog);
await context.SaveChangesAsync();
}
}
}
But it fails when it tries to write to the DB.
System.InvalidOperationException: 'A named connection string was used, but the name 'MyDbConnectionString' was not found in the application's configuration.
Should I be adding appsettings.json to the library project (This seems redundant, and incorrect)? What am I missing? How do I reference back to the web projects appsettings.json file?
Any help would be greatly appreciated.
Here is my startup
services.AddDbContext<MyContext>(options =>options.UseSqlServer(Configuration.GetConnectionString("MyDbConnectionString")));
***** HERE ARE CHANGES I HAVE MADE TO THE WORK *****
I have found the issue I believe so here we go.
Remove the following from MySsdCaseContext.
public MySsdCaseContext()
{
}
and keep this one..
public MySsdCaseContext(DbContextOptions<MySsdCaseContext> options) : base(options)
{
}
For the purposes of fixing this comment out the following from OnConfiguring.
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("name=MySsdCaseDb");
}
In startup.cs add the following inside ConfigureService method.
services.AddDbContext<MySsdCaseContext>(options
=>options.UseSqlServer(Configuration.GetConnectionString("MySsdCaseDb")));
This should prompt you to add a reference to MySsdCase.Core.Data class library. You don't currently have this. Basically put
the following at the top of startup.cs
using MySsdCase.Core.Data;
Ensure the following is inside MySsdCase.Web.cspoj
<ItemGroup>
<ProjectReference Include="..\MySsdCase.Core\MySsdCase.Core.csproj" />
</ItemGroup>
Do it like this...
public class EventLogRepository
{
private readonly MySsdCaseContext _context;
public async Task AddEventLogAsync(EventLog eventLog)
{
var myVar = await _context.Set<ClientDetails>()
.AsNoTracking()
.Select(p => p)
.Take(2)
.ToListAsync();
}
}
I think overall there was no reference to the DAL from the BL in startup.cs.