.NET Core 2.2 RawRabbit Serializer/Dependency Injection Issue - asp.net-core-2.2

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

Related

ASP.NET Migration from WebHostBuilder (Pre-.NET 3.0) to IHostBuilder + ConfigureWebHostDefaults (Post-.NET 3.0) causes API returning 404 error

We have a project that started on .NET Core 2.2 and recently was migrated to .NET 6. In this project we used WebHostBuilder because we used combination of Rest API and Hosted Services and we decided to re-implement our hosts to new Generic hosts that were introduced in .NET Core 3.
But after reimplementation of our WebHost to Generic Host + WebHostDefaults method combo all of our API calls started to return 404 not found error message as if Controllers were not found/mapped correctly and my ideas of how to fix it ran out.
Our HostBuilder implementation:
var host = builder
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults((webBuilder) =>
webBuilder.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
.UseWebHostConfiguration(ComponentName, commandLineArguments, out configuration)
.UseStartup(webHost => StartupClassFactory()))
.Build();
ConfigureServices implementation in Startup Class:
private void ConfigureServices(IServiceCollection services)
{
//Configure other non-API services
services
.AddMvc(options => options.EnableEndpointRouting = false)
.AddNewtonsoftJson(options => JsonSettings.SetSettings(options.SerializerSettings));
}
Configure implementation in Startup Class:
protected override void Configure(
IApplicationBuilder app,
ILoggerFactory loggerFactory,
IServiceProvider serviceProvider,
IHostApplicationLifetime applicationLifetime)
{
//Database Migration Stuff here
app.UseMiddleware<InquiryMetricLogHandlerMiddleware>();
app.UseMiddleware<ExceptionHandlerMiddleware>();
app.UseMiddleware<SeedingCheckMiddleware>();
if (QueryLocking)
{
QueryLockingMiddlewareApplicator(app);
}
app.UseMvc();
}
Controller snippet:
//Our Internal libraries
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MyProject
{
[ApiController]
[Route(Routes.ApiRoute1 + "/{id:guid}/" + Routes.ApiRoute2)]
public class CustomController : SqliteInquiryController<MyModel>
{
public TokensController(
DI arg1,
DI arg2,
DI arg3)
: base(arg1, arg2, arg3)
{
//Constructor stuff
}
[Route("/" + Routes.GetAllApiRoute), HttpGet, PaginationValidation]
public override async Task<IActionResult> GetList()
{
//Build Database LINQ query
return Ok(response);
}
}
}
When debugging and trying /GetAllApiRoute API call I found out, that requests go through all Middlewares and stop on UseMvc where it throws just 404 Not Found response so it seems like problem with registering of Controller or routing request to Controller.
Methods ConfigurateServices and Configurate have the same implementation as they had on .NET 2.2 and everything worked fine. So I guess something must have changed in WebHost configuration along the way from .NET 2.2 until .NET 6 which makes this code disfunctional but I can't figure out what and I also didn't find anything on the web what would help me.
Here is what I've tried but didn't help:
Replacing AddMvc() for AddControllers() and UseMvc() for UseEndpoints(endpoints => endpoints.MapControllers())
Omit Startup class and call Configure and ConfigureServices directly from the builder
Any help would be highly appreciated :)
For me the problem was that my HostBuilder was in different assembly (Library Project) than Controllers as it was used in multiple different projects. And apparently the logic of loading Controllers must have changed and it was looking for Controllers only in Assembly where HostBuilder was located. So adding AddApplicationPart into ConfigureServices fixed my problem and everything works fine now.
Solution Code:
services
.AddControllers()
.AddNewtonsoftJson(options => JsonSettings.SetSettings(options.SerializerSettings))
.AddApplicationPart(Assembly.GetEntryAssembly()); //Adding this will look for Controllers in your Entry Point assembly where most likely your Controllers are

xUnit test pass but getting "Catastrophic failure: System.ArgumentException"

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

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

Unity InterfacesInterceptor in .NET Core

I'll start out with the questions first and follow up with context:
Is there a version of Unity.Interception available that is compatible with .NET Core?
Is there a .NET Core compatible alternative to Unity.Interception?
I am looking at using the Microsoft.Practices.Unity.InterceptionExtension.InterfaceInterceptor to short-circuit calls to certain interfaces (example code below), but it seems that the suggested NuGet package, Unity.Interception 4.0.1, is not compatible with .NET Core.
I have made an attempt to shoe-horn in the usage of Unity.Interception 4.0.1, as the code snippets used works fine in classic .NET; but as mentioned I am running into problems with .NET Core:
Install-Package : Package Unity.Interception 4.0.1 is not compatible with netcoreapp1.1 (.NETCoreApp,Version=v1.1). Package Unity.Interception 4.0.1 supports: net45 (.NETFramework,Version=v4.5
)
I tried to circumvent this by adding net451 to the PackageTargetFallback list:
<PackageTargetFallback>$(PackageTargetFallback);net451;dnxcore50;portable-net451+win8</PackageTargetFallback>
This allowed me to install the package, but it then complains something fierce about needing a reference to mscorlib:
Error CS0012
The type 'Type' is defined in an assembly that is not referenced. You must add a reference to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
I'm not going to attempt to reference in the Classic .NET framework into a .NET Core application, so I'm pretty much at a dead end here.
Example code:
public class Interceptions
{
public static object CreateCustomInterceptedProxy(Type type)
{
var interceptor = new InterfaceInterceptor();
var proxy = interceptor.CreateProxy(type, null);
var interceptionBehavior = new CustomInterceptionBehavior();
proxy.AddInterceptionBehavior(interceptionBehavior);
return proxy;
}
}
public class CustomInterceptionBehavior : IInterceptionBehavior
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
object response = null; // replace with stuff that builds an actual object
return input.CreateMethodReturn(response, new object[] { });
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public bool WillExecute => true;
}
I know the question is for around a month ago, but I thought it might be useful for other developers as well (because It's been a nightmare for me).
I have forked out Unity project and ported that to .Net Core 2.0. You can find it under this repository:
https://github.com/Chavoshi/Unity.NetCore
And also these are the nuget packages:
https://www.nuget.org/packages/Unity.NetCore/
https://www.nuget.org/packages/Unity.Interception.NetCore/
P.S: The only part which I was not able to port is TransparentProxyInterception that uses .Net Remoting which is totally discontinued in .Net Core.
Unfortunately you have to use 3rd party libraries like:
Unity fork: https://www.nuget.org/packages/Unity.Interception.NetCore/
Dora Interception: https://www.nuget.org/packages/Dora.Interception/ it has a detailed usage documentation here.
It seems Castle.Core's DynamicProxy is what I needed:
using Castle.DynamicProxy;
public class CustomInterceptor : IInterceptor
{
public static object CreateCustomInterceptedProxy(Type type)
{
var proxyGenerator = new ProxyGenerator();
var interceptor = new Interceptor();
var proxy = proxyGenerator.CreateInterfaceProxyWithoutTarget(type, interceptor);
return proxy;
}
}
public class CustomInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
object returnValue; // Do stuff to populate return value
invocation.ReturnValue = returnValue;
}
}

IdentityManager with VNext

Has anyone tried using IdentityManager with vNext?
I'm having problems with the app.UseIdentityManager(IdentityManagerOptions) extension method.
It doesn't exist.
So I tried using the extension method made for UseIdentityServer (found here) by changing all the server related aspects to manager.
When I do that, I get the System.NullReferenceException in line 43.
Any kind of advice on how to go about with the extension method will be really appreciated
I am using ASPNET 5 beta6 and I got this to work.
Try using this updated IApplicationBuilder extension found in the Samples repo on dev branch. Repurpose the method to accept IdentityManagerOptions rather than IdentityServerOptions and edit the builder to UseIdentityManager
In short here is what my extension method looks like
public static class IApplicationBuilderExtensions
{
public static void UseIdentityManager(this IApplicationBuilder app, IdentityManagerOptions options)
{
app.UseOwin(addToPipeline =>
{
addToPipeline(next =>
{
var builder = new AppBuilder();
var provider = app.ApplicationServices.GetService<IDataProtectionProvider>();
builder.Properties["security.DataProtectionProvider"] =
new DataProtectionProviderDelegate(purposes =>
{
var dataProtection = provider.CreateProtector(string.Join(",", purposes));
return new DataProtectionTuple(dataProtection.Protect, dataProtection.Unprotect);
});
builder.UseIdentityManager(options);
var appFunc =
builder.Build(typeof (Func<IDictionary<string, object>, Task>)) as
Func<IDictionary<string, object>, Task>;
return appFunc;
});
});
}
}
I'm using vNext and I've noticed that many things have changed and will continue to change.
For my own needs I've been able to get identity up and running fairly easily and there are two steps that I've had to take to get it running properly. What I've done should work for you as well.
In your StartUp.cs you will need to make sure you add the following to the ConfigureServices method:
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
In addition to that you will need to configure your app to use identity and to do this you need to do the following in your Configure() method:
app.UseIdentity();

Resources