SignalR .Net Client with MessagePack - AddMessagePackProtocol Method Unrecognised in IHubConnectionBuilder - signalr

New user, trying to learn SignalR and Blazor Server, hoping somebody can help with this query. Struggling with getting the SignalR .NET Client to use MessagePack protocol in the Blazor Server Page.
.csproj Packages Installed
<ItemGroup>
<PackageReference Include="Autofac" Version="5.2.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="6.0.0" />
<!-- <PackageReference Include="MessagePack" Version="1.9.3" /> -->
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="3.1.7" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="3.1.7" />
</ItemGroup>
Originally I had installed 3.1.8 of SingalR Client and MessagePack packages. However, I have also tried downgrading to 3.1.7 and the issue still occurs.
This segment of code:
hubConnection = new HubConnectionBuilder()
.WithUrl(hubUrl)
.AddMessagePackProtocol()
.Build();
causes a build error:
error CS1061: 'IHubConnectionBuilder' does not contain a definition for 'AddMessagePackProtocol' and no accessible extension method 'AddMessagePackProtocol' accepting a first argument of type 'IHubConnectionBuilder' could be found (are you missing a using directive or an assembly reference?).....
Can anybody help? Am I missing an assembly #using reference?
Blazor Server Page
#page "/"
#using System.Threading;
#using System.Collections.Generic;
#using Microsoft.AspNetCore.SignalR.Client;
#using WebApp.Data;
#inject NavigationManager NavigationManager
<h1>Blazor Server App</h1>
<div>Latest message is => #_latestMessage</div>
<div id="scrollbox">
#foreach (var item in _messages)
{
<div>
<div>#item</div>
</div>
}
<hr />
</div>
#code {
private HubConnection hubConnection;
private string _latestMessage = "";
private List<string> _messages = new List<string>();
public bool IsConnected => hubConnection.State == HubConnectionState.Connected;
protected override async Task OnInitializedAsync()
{
var hubUrl = NavigationManager.BaseUri.TrimEnd('/') + "/motionhub";
// Uri uri = NavigationManager.ToAbsoluteUri("/motionhub");
try
{
hubConnection = new HubConnectionBuilder()
.WithUrl(hubUrl)
.AddMessagePackProtocol()
.Build();
hubConnection.On<string>("SendMotionDetection", ReceiveMessage);
await hubConnection.StartAsync();
Console.WriteLine("Index Razor Page initialised, listening on signalR hub url => " + hubUrl.ToString());
Console.WriteLine("Hub Connected => " + IsConnected);
}
catch (Exception e)
{
Console.WriteLine("Encountered exception => " + e);
}
}
private void ReceiveMessage(string message)
{
try
{
Console.WriteLine("Hey! I received a message");
_latestMessage = message;
_messages.Add(_latestMessage);
StateHasChanged();
}
catch (Exception ex)
{
Console.Error.WriteLine("An exception was encountered => " + ex.ToString());
}
}
}

Finally, got this to compile by adding:
#using Microsoft.Extensions.DependencyInjection;
Hope this saves some time for other new users that experience similar issue.

Just to clarify the correct answer already given by #anon_dc3spp it should be noted that you:
Need to have the Microsoft.AspNetCore.SignalR.Protocols.MessagePack Nuget Package installed on both the client and server.
Then you would use his reference shown below on the intended razor page... or maybe add it to your imports page:
#using Microsoft.Extensions.DependencyInjection

Related

Azure Functions and AppInsights RequestTelemetry

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).

DevExpress routing appears to break with dotnet core 3.1

I have the following DxDatagrid block in my dotnet core webapp index.cshtml page:
#(Html.DevExtreme().DataGrid<UserModel>()
.ID("grid-container")
.ShowBorders(true)
.DataSource(d => d.Mvc().Controller("UserSearch").LoadAction("Get").Key("UserId"))
.Selection(s => s
.Mode(SelectionMode.Multiple)
.SelectAllMode(SelectAllMode.Page)
)
With this code in place and using dotnet core 2.2 the datasource makes a call to:
http://localhost:5000/api/UserSearch/Get?skip=0&take=10&requireTotalCount=true&_=1600859370033
Having updated to dotnet core 3.1 and updated the DevExpress references in the csproj and _Layout.cshtml files, the routing now attempts to call:
http://localhost:5000/?skip=0&take=10&requireTotalCount=true&_=1600859693687
The startup.cs is this:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using AccessUsers.Middleware;
using AccessUsers.Models;
using Microsoft.AspNetCore.HttpOverrides;
namespace WebAppTest
{
public class Startup
{
private readonly IConfiguration _config;
private readonly AppSettings _appSettings;
public Startup(IConfiguration config)
{
_config = config;
_appSettings = _config.Get<AppSettings>();
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false;
// options.MinimumSameSitePolicy = SameSiteMode.None;
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
options.OnAppendCookie = cookieContext => cookieContext.CookieOptions.SameSite = SameSiteMode.Unspecified;
options.OnDeleteCookie = cookieContext => cookieContext.CookieOptions.SameSite = SameSiteMode.Unspecified;
});
services.Configure<AppSettings>(_config);
services.AddSingleton<APIService>();
services.AddSingleton<UserService>();
services.AddSingleton<ShipToService>();
services.AddApplicationInsightsTelemetry();
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddSession();
services.AddMemoryCache();
services.AddRazorPages().AddNewtonsoftJson(options => {
options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
}).AddXmlSerializerFormatters();
services.UseOpenIDConnectMiddleware(new OpenIDConnectMiddlewareOptions
{
BaseUrl = _appSettings.API.BaseUrl,
AppName = _appSettings.AppName,
ClientId = _appSettings.API.ClientId,
ClientSecret = _appSettings.API.ClientSecret,
Secure = !_appSettings.Local
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedProto
});
if (_appSettings.Local)
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
app.UseGlobalLoginMiddleware();
app.UseHttpsRedirection();
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints => {
endpoints.MapRazorPages();
});
CultureInfo[] allCultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
string location = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
var supportedCultures = allCultures.Where(c => Directory.Exists(Path.Combine(location, c.Name)) && c.LCID != 127).ToList();
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});
}
}
}
The csproj contains this:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="3.1.6" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.7" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="6.7.1" />
<PackageReference Include="DevExtreme.AspNet.Data" Version="2.7.1" />
<PackageReference Include="DevExtreme.AspNet.Core" Version="20.1.7" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.7.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.7.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.14.0" />
<PackageReference Include="Amazon.Lambda.AspNetCoreServer" Version="5.0.0" />
</ItemGroup>
</Project>
The controller.cs contains this:
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using AccessUsers.Models;
using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace WebAppTest.Pages
{
[Route("api/[controller]/[action]")]
public class UserSearchController : Controller
{
private readonly UserService _userService;
public UserSearchController(UserService userService)
{
_userService = userService;
}
[HttpGet]
public object Get(DataSourceLoadOptions loadOptions)
{
var result = DataSourceLoader.Load(GetProfiles(user:new UserModel(),useDummyData: true), loadOptions);
return result;
}
The _Layout.cshtml contains this:
<script src="https://cdn3.devexpress.com/jslib/20.1.7/js/dx.all.js" integrity="sha384-LAn+t9UxSqkm8biNuoUbJcohKoYmbiFRfVLERIJ4I3RyEpAIBizEcIztuXPG9Cqg sha512-OAjfsw+eXv345AD9H6kDJLChXetpJD6ChGgDvjVIEumiHYulOLXIO/Do5gxljW2GUgpObic42JyS8a0wZqb1Fw==" crossorigin="anonymous"></script>
<script src="https://cdn3.devexpress.com/jslib/20.1.7/js/dx.aspnet.mvc.js" integrity="sha384-5rtF4jUX5Hez5YwkW7PHC/0XplJQS26qVUCfec8fBX0IkoR1y35EXHkZDbgeMh3x sha512-0eJebJTnN45FCtUOrVqxk5p73OMWsx94vLQpnlRtDp/CKbssiUR0j0os+0y01fvzDtdtnEKSeau32g30fgtrYQ==" crossorigin="anonymous"></script>
As specified here:
https://js.devexpress.com/Documentation/Guide/Common/Distribution_Channels/CDN/
I'm sure it's the change to dotnet core 3.1 which caused the routing to break because the functionality of the application hasn't changed, but I can't see what specifically breaks it.
Startup.ConfigureServices doesn't add support for controllers, only for Razor Pages with :
services.AddRazorPages().AddNewtonsoftJson(options => {
...
}).AddXmlSerializerFormatters();
From the Remarks in the method's documentation
This method configures the MVC services for the commonly used features for pages.
To add services for controllers for APIs call AddControllers(IServiceCollection).
The controller is never registered right now, so the code that tries to generate the action URL
.DataSource(d => d.Mvc().Controller("UserSearch").LoadAction("Get")
fails to find anything and returns an empty string.
To fix this, add controller support :
services.AddControllers().AddNewtonsoftJson(options => {
...
}).AddXmlSerializerFormatters();
services.AddRazorPages();
Controllers should be added in the endpoint routing code in Configure as well, with MapControllers :
app.UseEndpoints(endpoints => {
endpoints.MapRazorPages();
endpoints.MapControllers();
});

Can't bind service implementation using DI inside function with ServiceBusTrigger parameter in .net core Azure Web Job

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;
}
}
}

.NET Core 2.2 RawRabbit Serializer/Dependency Injection Issue

I have microservice based on .NET Core 2.2. I am using RawRabbit (version 2.0.0-beta9) as the service bus. The following packages were installed with it:
<PackageReference Include="RawRabbit" Version="2.0.0-beta9" />
<PackageReference Include="RawRabbit.DependencyInjection.ServiceCollection" Version="2.0.0-beta9" />
<PackageReference Include="RawRabbit.Operations.Publish" Version="2.0.0-beta9" />
<PackageReference Include="RawRabbit.Operations.Subscribe" Version="2.0.0-beta9" />
This is what my controller looks like:
private readonly IBusClient _busClient;
//...constructor that inits the _busClient
[HttpPost("")]
public async Task<IActionResult> Post([FromBody] CreateActivity model)
{
model.Id = Guid.NewGuid();
await _busClient.PublishAsync(model); //Exception thrown here
return Accepted($"Activities/{model.Name}");
}
The problem occurs when the code tries to do the following:
await _busClient.PublishAsync(model);
The exception I get is:
MissingMethodException: Method not found: 'Void Newtonsoft.Json.JsonSerializer.set_TypeNameAssemblyFormat(System.Runtime.Serialization.Formatters.FormatterAssemblyStyle)'.
RawRabbit.DependencyInjection.RawRabbitDependencyRegisterExtension+<>c.b__0_1(IDependencyResolver resolver)
....... more text .......
RawRabbit.BusClient.InvokeAsync(Action pipeCfg, Action contextCfg, CancellationToken token)
Actio.Api.Controllers.ActivitiesController.Post(CreateActivity model) in ActivitiesController.cs
followed by the code of my Post action as showed above.
The following action works as expected:
[HttpGet]
public IActionResult Get()
{
return Content("Hello from Actio API!");
}
I assumed it's because this action does not use the IBusClient. So, the problem had to be with RawRabbit. I googled the issue and found an issue on the RawRabbit GitHub repo. The solution was to upgrade to a newer version on RawRabbit. So, I tried upgrading to 2.0.0-rc1 but I got some syntax errors. I have defined a class Extensions that defines the following method:
public static Task WithCommandHandlerAsync<TCommand>(this IBusClient bus,
ICommandHandler<TCommand> handler) where TCommand: ICommand
=> bus.SubscribeAsync<TCommand>(msg => handler.HandleAsync(msg),
ctx => ctx.UseConsumerConfiguration(cfg =>
cfg.FromDeclaredQueue(q => q.WithName(GetQueueName<TCommand>()))));
The problem seems to be with UseConsumerConfiguration. The error says:
ISubscribe Context does not contain a definition for UseConsumerConfiguration
Additional info: I am following the .NET Microservices Course by Packt Publishing. This code seems to be working fine for them with the exact same packages.
For anyone in the future, you have to do the following:
RawRabbit 2.0.0-rc5 (latest at the time of writing). Include Prelease versions.
Change UseConsumerConfiguration -> UseSubscribeConfiguration
Install RawRabbit.Operations.Subscribe because SubscribeAsync will no longer be recognized
Final output should look like this:
public static Task WithCommandHandlerAsync<TCommand>(this IBusClient bus,
ICommandHandler<TCommand> handler) where TCommand : ICommand
=> bus.SubscribeAsync<TCommand>(msg => handler.HandleAsync(msg),
ctx => ctx.UseSubscribeConfiguration(cfg =>
cfg.FromDeclaredQueue(q => q.WithName(GetQueueName<TCommand>()))));
Update RawRabbit version to 2.0.0-rc5
After that use UseSubscribeConfiguration instead of UseConsumerConfiguration

Nancy 500 server error with dotnetcore and kestrel

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!"); });

Resources