I currently have a solution with about 1000 unit/integration tests using MSTest runner. The problem Im experiencing with AutoMapper is that when I have VS run all tests in the solution, I'll randomly get a few unit tests fail due to the following automapper exception:
AutoMapper.AutoMapperMappingException:
Mapping types:
String -> String
System.String -> System.String
Destination path:
CatalogResource.CultureCode
Source value:
en-US ---> System.InvalidCastException: Unable to cast object of type 'Model.Catalog' to type 'Model.CatalogResource'.
In the code I dont have a Catalog to CatalogResource map nor am I trying to map them to each other. This type of exception doesnt happen in PROD, doesnt happen for the integration tests, doesnt happen every time I run the tests and when it does happen, it is always different tests that fail. Also, if I run only the tests that just failed, they always pass. I have a hard time consistently reproducing this locally but it happens more frequently on the build server, which is a pain because it prevents the build from getting automatically promoted to the next environment.
I've also tried adding this to the tests but it has not solved the problem:
[ClassInitialize]
public static void ClassInitialize(TestContext context)
{
Mapper.Reset();
}
Any ideas? We've had 4 different people take a stab at this to no avail so Im resorting to you great folks for help now.
Thanks!
EDIT:
I currently initialize the configuration using a static class that gets called inside a static constructor for the service. I.E.
static MyService()
{
AutoMapperBootstrapper.Initialize();
}
...
internal static class AutoMapperBootstrapper
{
public static void Initialize()
{
ConfigureMappings();
#if DEBUG
Mapper.AssertConfigurationIsValid();
#endif
}
}
EDIT #2:
While doing some more tinkering today, I notice that these random failures happen only for <IDataReader, something else> maps. For example:
Mapper.CreateMap<IDataReader, Catalog>()
.ForMember(m => m.CatalogID, opt => opt.MapFrom(src => src["CatalogID"]))
.ForMember(m => m.Title, opt => opt.MapFrom(src => src["Title"]))
.ForMember(m => m.DateCreatedUTC, opt => opt.MapFrom(src => src["DateCreatedUTC"]))
.ForMember(m => m.DateModifiedUTC, opt => opt.MapFrom(src => src["DateModifiedUTC"]))
...
Not sure what to make of it yet but it seemed relevant.
I presume you call AutoMapperBootstrapper.Initialize from your unit tests, and the ONLY location you have the mapping configuration is in ConfigureMappings? I can't explain your issue, but you obviously have some leakage between your unit tests somewhere. I have a similar setup, and this is what I do...
My initialisation code is
public static class MappingConfiguration
{
public static void RegisterMappings()
{
Mapper.Initialize(x =>
{
x.AddProfile<MapperProfileOne>();
x.AddProfile<MapperProfileTwo>();
});
}
}
This is only ever called by the application (I dont bother testing the RegisterMappings method as it only has the single Initialize call and I trust that AutoMapper works. My unit tests (to test my mapping configuration) are as follows:
[Test]
public void Initialise_ProfileOne_GeneratesNoErrors()
{
Mapper.Initialize(x => x.AddProfile<MapperProfileOne>());
Mapper.AssertConfigurationIsValid();
}
[Test]
public void Initialise_ProfileTwo_GeneratesNoErrors()
{
Mapper.Initialize(x => x.AddProfile<MapperProfileTwo>());
Mapper.AssertConfigurationIsValid();
}
An example of a profile is:
public class MapperProfileOne : Profile
{
protected override void Configure()
{
Mapper.CreateMap<Source, Destination>();
}
}
I'm wondering that if you're calling the AutoMapperBootstrapper method from your unit tests that its somehow getting confused (there's not enough detail in the question to determine this for certain). I don't think it should, but hopefully there's at least something in the code above that might magically fix the issue for you.
Related
I'm making use of MassTransit to receive some messages from a client's application, and redistribute the message within our environment with some routing headers added.
Whilst we are processing a high amount of messages, not all consuming applications are going to be interested in the whole set of the messages. As such the various consumers are configured with the SNS/SQS FilterPolicy attribute to ensure that only the messages we care about are consumed.
The issues I'm experiencing comes about when using the WebApplicationFactory and the IServiceCollection AddMassTransitTestHarness extension method.
The first issue might be down to my misunderstanding. As I'm using SQS/SNS specific functionality, the InMemoryTestHarness is unsuitable. I'm calling the below snippet when configuring my MassTransitTestHarness:
services.AddMassTransitTestHarness( x =>
{
RegisterConsumers( x );
x.UsingAmazonSqs( ( context, factoryConfigurator ) =>
{
factoryConfigurator.Host( new Uri( "amazonsqs://localhost:4566" ),
h =>
{
h.Config( new AmazonSimpleNotificationServiceConfig { ServiceURL = serviceUrl } );
h.Config( new AmazonSQSConfig { ServiceURL = serviceUrl } );
h.AccessKey( "test" );
h.SecretKey( "test" );
} );
RegisterReceiveEndpoints( factoryConfigurator, context );
} );
} );
protected override void RegisterConsumers( IRegistrationConfigurator configurator )
{
configurator.AddConsumer<MovementConsumer>();
}
protected override void RegisterReceiveEndpoints( IAmazonSqsBusFactoryConfigurator factoryConfigurator, IRegistrationContext context )
{
factoryConfigurator.ReceiveEndpoint( $"{ServiceConstants.ServiceName}-test-movement", endpointConfigurator =>
{
endpointConfigurator.ConfigureConsumer<MovementConsumer>( context );
endpointConfigurator.QueueSubscriptionAttributes["FilterPolicy"] = $"{{\"RoutingKey\": [\"null\"]}}";
} );
}
My first question with this approach is that is it necessary to re-register consumers? Ideally I'd like to call AddMassTransitTestHarness and just have it replace the already existing Bus with the TestHarness, but I was finding my consumers weren't being called. Having to re-register the endpoints in both the tests project and the actual project is a burden I'd like to avoid any other developers on this project having.
The second question I have is with regards to asserting against what's been published. I'm experiencing inconsistent results with the below code:
await busTestHarness.Start();
await busTestHarness.Bus.Publish( message, CancellationToken.None );
await busTestHarness.InactivityTask;
//await Task.Delay( TimeSpan.FromSeconds( 2 ) );
busTestHarness.Published.Select<T>().Any( publishedMessage => publishedMessage.Context.Headers.Any( headerValue => headerValue.Key == "RoutingKey" && (string) headerValue.Value == expectedHeader ) ).ShouldBeTrue();
Sometimes the above assertion fails. I am expecting my consumer to publish a new message with routing headers (I am not asserting against the message I publish in the test).
I've found that whilst still flakey, the 2 second delay seems to reduce the rate of failure. Is my usage of InactivityTask correct? Is there anything else I should be waiting for.
Thanks for any help, I've scoured the docs and watched the video on testing with WebApplicationFactory. I've mirrored what's done in there as best as I can. The major difference being that I am not expecting any responses from my messages.
I'm trying to learn by doing and it has been a fun struggle so far :D
I've finally got my project to scaffold my DB but it populates a warning in the code.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer("Server=<servername>;Database=<databaseName>;Trusted_Connection=True");
}
}
I've tried to update it to use the "DefalutConnection" in my appsettings.json file but it doesn't recognize Configuration. I've imported the namespace using Microsoft.Extensions.Configuration; but that still doesn't resolve the issue.
I'm trying to get something akin to the following: options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
Not sure which direction to go in resolving this. Is this a non-issue or am I missing adding something to get this to pull from appsettings.json?
My guess is that the DbCOntextOptionsBuilder doesn't have a method for Configuration and I would need to build it out myself... but I'm not sure how to do that either.
Thanks for your time/attention on this.
Solution Shown to Assist Others, See Marked Answer Below
Error
Unable to create an object of type 'ProfileContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
add public IConfiguration Configuration {get;}
inject it in your constructor
public ContextDbName(IConfiguration configuration)
{
Configuration = configuration;
}
update your OnConfiguring method
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
}
}
I think you need to inject Configuration into your DbContext constructor.
Running with the original script, created by Scaffolding, in the newly created context file I ran into other issues regarding dependency injection. This got me thinking more about Microsofts Documents.
So I added an injection into my startup file for my newly created Context class and like magic, it worked :D
Startup.cs:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddDbContext<ProfileContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
You can use scaffold like this:
Scaffold-DbContext -Connection "This is the connectiostring" -Provider Microsoft.EntityFrameworkCore.SqlServer -OutputDir Data/Entities -ContextDir Data -Context "This is the contextname" -NoOnConfiguring -f
For your case -NoOnConfiguring will prevent to create the code with connectionstring (optionsBuilder.UseSqlServer)
In a SpringBoot application, I have the following configuration:
axon:
axonserver:
servers: "${AXON_SERVER:localhost}"
serializer:
general: jackson
messages: jackson
events: jackson
logging.level:
org.axonframework.modelling.saga: debug
Downsizing the scenario to bare minimum, the relevant portion of Saga class:
#Slf4j
#Saga
#ProcessingGroup("AuctionEventManager")
public class AuctionEventManagerSaga {
#Autowired
private transient EventScheduler eventScheduler;
private ScheduleToken scheduleToken;
private Instant auctionTimerStart;
#StartSaga
#SagaEventHandler(associationProperty = "auctionEventId")
protected void on(final AuctionEventScheduled event) {
this.auctionTimerStart = event.getTimerStart();
// Cancel any pre-existing previous job, since the scheduling thread might be lost upon a crash/restart of JVM.
if (this.scheduleToken != null) {
this.eventScheduler.cancelSchedule(this.scheduleToken);
}
this.scheduleToken = this.eventScheduler.schedule(
this.auctionTimerStart,
AuctionEventStarted.builder()
.auctionEventId(event.getAuctionEventId())
.build()
);
}
#EndSaga
#SagaEventHandler(associationProperty = "auctionEventId")
protected void on(final AuctionEventStarted event) {
log.info(
"[AuctionEventManagerSaga] Current state: {scheduleToken={}, auctionTimerStart={}}",
this.scheduleToken,
this.auctionTimerStart
);
}
}
In the final compiled class, we will end up having 4 properties: log (from #Slf4j), eventScheduler (transient, #Autowired), scheduleToken and auctionTimerStart.
For reference information, here is a sample of the general approach I've been using for both Command and Event classes:
#Value
#Builder
#JsonDeserialize(builder = AuctionEventStarted.AuctionEventStartedBuilder.class)
public class AuctionEventStarted {
AuctionEventId auctionEventId;
#JsonPOJOBuilder(withPrefix = "")
public static final class AuctionEventStartedBuilder {}
}
When executing the code, you get the following output:
2020-05-12 15:40:01.180 DEBUG 1 --- [mandProcessor-4] o.a.m.saga.repository.jpa.JpaSagaStore : Updating saga id c8aff7f7-d47f-4616-8a96-a40044cb7e3b as {}
As soon as the general serializer is changed to xstream, the content is serialized properly, but I face another issue during deserialization, since I have private static final class Builder classes using Lombok.
So is there a way for Axon to handle these scenarios:
1- Axon to safely manage Jackson to ignore #Autowired, transient and static properties from #Saga classes? I've attempted to manually define #JsonIgnore at non-state properties and it still didn't work.
2- Axon to safely configure XStream to ignore inner classes (mostly Builder classes implemented as private static final)?
Thanks in advance,
EDIT: I'm pursuing a resolution using my preferred serializer: JSON. I attempted to modify the saga class and extend JsonSerializer<AuctionEventManagerSaga>. For that I implemented the methods:
#Override
public Class<AuctionEventManagerSaga> handledType() {
return AuctionEventManagerSaga.class;
}
#Override
public void serialize(
final AuctionEventManagerSaga value,
final JsonGenerator gen,
final SerializerProvider serializers
) throws IOException {
gen.writeStartObject();
gen.writeObjectField("scheduleToken", value.eventScheduler);
gen.writeObjectField("auctionTimerStart", value.auctionTimerStart);
gen.writeEndObject();
}
Right now, I have something being serialized, but it has nothing to do with the properties I've defined:
2020-05-12 16:20:01.322 DEBUG 1 --- [mandProcessor-0] o.a.m.saga.repository.jpa.JpaSagaStore : Storing saga id c4b5d94c-7251-40a5-accf-332768b1cacd as {"delegatee":null,"unwrappingSerializer":false}
EDIT 2 Decided to add more insight into the issue I experience when I switch general to use XStream (even though it's somewhat unrelated to the main issue described in the title).
Here is the issue it complains to me:
2020-05-12 17:08:06.495 DEBUG 1 --- [ault-executor-0] o.a.a.c.command.AxonServerCommandBus : Received command response [message_identifier: "79631ffb-9a87-4224-bed3-a957730dced7"
error_code: "AXONIQ-4002"
error_message {
message: "No converter available\n---- Debugging information ----\nmessage : No converter available\ntype : jdk.internal.misc.InnocuousThread\nconverter : com.thoughtworks.xstream.converters.reflection.ReflectionConverter\nmessage[1] : Unable to make field private static final jdk.internal.misc.Unsafe jdk.internal.misc.InnocuousThread.UNSAFE accessible: module java.base does not \"opens jdk.internal.misc\" to unnamed module #7728643a\n-------------------------------"
location: "1#600b5b87a922"
details: "No converter available\n---- Debugging information ----\nmessage : No converter available\ntype : jdk.internal.misc.InnocuousThread\nconverter : com.thoughtworks.xstream.converters.reflection.ReflectionConverter\nmessage[1] : Unable to make field private static final jdk.internal.misc.Unsafe jdk.internal.misc.InnocuousThread.UNSAFE accessible: module java.base does not \"opens jdk.internal.misc\" to unnamed module #7728643a\n-------------------------------"
}
request_identifier: "2f7020b1-f655-4649-bbe0-d6f458b3c2f3"
]
2020-05-12 17:08:06.505 WARN 1 --- [ault-executor-0] o.a.c.gateway.DefaultCommandGateway : Command 'ACommandClassDispatchedFromSaga' resulted in org.axonframework.commandhandling.CommandExecutionException(No converter available
---- Debugging information ----
message : No converter available
type : jdk.internal.misc.InnocuousThread
converter : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
message[1] : Unable to make field private static final jdk.internal.misc.Unsafe jdk.internal.misc.InnocuousThread.UNSAFE accessible: module java.base does not "opens jdk.internal.misc" to unnamed module #7728643a
-------------------------------)
Still no luck on resolving this...
I've worked on Axon systems where the only used Serializer implementation was the JacksonSerializer too. Mind you though, this is not what the Axon team recommends. For messages (i.e. commands, events and queries) it makes perfect sense to use JSON as the serialized format. But switching the general Serializer to jackson means you have to litter your domain logic (e.g. your Saga) with Jackson specifics "to make it work".
Regardless, backtracking to my successful use case of jackson-serialized-sagas. In this case we used the correct match of JSON annotations on the fields we desired to take into account (the actual state) and to ignore the one's we didn't want deserialized (with either transient or #JsonIgnore). Why both do not seem to work in your scenario is not entirely clear at this stage.
What I do recall is that the referenced project's team very clearly decided against Lombok due to "overall weirdnes" when it comes to de-/serialization. As a trial it thus might be worth to not use any Lombok annotations/logic in the Saga class and see if you can de-/serialize it correctly in such a state.
If it does work at that moment, I think you have found your culprit for diving in further search.
I know this isn't an exact answer, but I hope it helps you regardless!
Might be worthwhile to share the repository where this problems occurs in; might make the problem clearer for others too.
I was able to resolve the issue #2 when using XStream as general serializer.
One of the Sagas had an #Autowired dependency property that was not transient.
XStream was throwing some cryptic message, but we managed to track the problem and address it.
As for JSON support, we had no luck. We ended up switched everything to XStream for now, as the company only uses Java and it would be ok to decode the events using XStream.
Not the greatest solution, as we really wanted (and hoped) JSON would be supported properly out of the box. Mind you, this is in conjunction with using Lombok which caused for the nuisance in this case.
I have this formatter in my .NET Core 3.1 project (which I recently upgraded from 2.1):
public class JilOutputFormatter : TextOutputFormatter {
public JilOutputFormatter() =>
JilFormatterConfig.AddSupportedHeaders(SupportedMediaTypes, SupportedEncodings);
public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) {
using (var writer = new StreamWriter(context.HttpContext.Response.Body)) {
JSON.Serialize(context.Object, writer, MyOptions);
writer.Flush();
}
return Task.FromResult(true);
}
}
And I'm adding it to pipeline with this snippet:
services.AddMvcCore(o => {
o.OutputFormatters.Insert(0, new JilOutputFormatter());
}).AddOthersBlahBlah();
It was working like a charm when the application was on 2.1. But now on 3.1 I'm getting this error:
An unhandled exception occurred while processing the request.
InvalidOperationException: Synchronous operations are disallowed. Call
WriteAsync or set AllowSynchronousIO to true instead.
I tried to async the write operation, but can't find the method on Jil. Do you have any idea please?
NOTE: I know there are some answers - like this one - that are saying how to AllowSynchronousIO. But I'm interested on how to async write in Jil.
You'll have to use the 3.0 alpha versions. Jil doesn't even include the word Task in the source code in the latest stable version, 2.17 (or Github search is having some issues).
Version 3.0 uses Pipelines directly. You can use the SerializeAsync(T, PipeWriter , Encoding, Options, CancellationToken). Maybe you can work with HttpContext.Response.BodyWriter. I haven't tested this though.
Eg :
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context,
Encoding selectedEncoding)
{
var data=context.Object;
var writer=contest.Response.BodyWriter;
await JSON.SerializeAsync(data,writer,selectedEncoding);
}
Errors can revolve around ReadAsync, WriteAsync, and FlushAsync with outputs similar to what is listed below.
Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.
Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.
Synchronous operations are disallowed. Call FlushAsync or set AllowSynchronousIO to true instead.
As a temporary workaround, you can set the value of AllowSynchronousIO in your ConfigureServices method found in your Startup class.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<KestrelServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
// If using IIS:
services.Configure<IISServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
// other services
}
It isn’t a great workaround, but it will keep you moving forward. The better solution is to upgrade your libraries and perform all your actions asynchronously.
See the detailed post .NET Core 3.0 AllowSynchronousIO Workaround by Khalid Abuhakmeh
TLDR: As of Dotnet Core 5.0, the default web-server (Kestral) is designed to perform only Async Level work to be the most performant. Enable Sync within Kestral.
Rational: Due to to the majority of software being more IO Dependent than CPU Dependent, Async Programming allows for the system to perform other work, while waiting for the IO to complete (IE; Writing to Disk, Reading something from the network).
Place this within Startup.cs within the ConfigurationService function.
services.Configure<KestrelServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
I have a web application developed in ASP.NET 2010. I have used the Dependency Injection with StructureMap in ASP.NET MVC. I'm trying to get started with Structure Map. I'm using
I've built a simple boot strapper, but when I run the website I get the following error:
StructureMap.Configuration.DSL.Expressions.CreatePluginFamilyExpression`1[System.Web.Mvc.IActionInvoker].Use:
type argument
'TestWebsite.Web.Controllers.Factories.InjectingActionInvoker'
violates the constraint of type parameter 'CONCRETETYPE'.
Code Block:
public static void ConfigureStructureMap()
{
ObjectFactory.Initialize(x =>
{
//registry per assembly recommended
x.AddRegistry<WebRegistry>();
x.AddRegistry<ServiceRegistry>();
x.AddRegistry<SHARE.Data.DataRegistry>();
});
//if a class needs configuring on load then this is done here. Inherit from IStartUpTask
ObjectFactory.GetAllInstances<IStartUpTask>()
.Where(x => x.IsEnabled).ToList()
.ForEach(t => t.Configure());
//This checks all is well. Not ideal to do in application_start though cause of calls to request object....
//ObjectFactory.AssertConfigurationIsValid();
}
public class WebRegistry : Registry
{
public WebRegistry()
{
For<IFormsAuthentication> ().Use<FormsAuthenticationService>();
For<IAuthentication>().Use<BasicMembership>();
Scan(x =>
{
x.AssemblyContainingType<IStartUpTask>();
x.AddAllTypesOf<IStartUpTask>();
x.WithDefaultConventions();
});
For<IActionInvoker>().Use<InjectingActionInvoker>();
SetAllProperties(c =>
{
c.OfType<IActionInvoker>();
c.WithAnyTypeFromNamespaceContainingType<UserService>(); //our services
c.WithAnyTypeFromNamespaceContainingType<AdminCookies>(); //cookie services
});
}
Could anyone please suggest on this issue. how it could be resolved? I am really getting troubled with it and need to resolve it asap. Any help would be greatly appreciated.
Thanks
Deepak
I do the following changes to run:
Remove the reference of MVC 3.0 DLL from website
Add the reference of MVC 2.0 DLL in website
Run the project and its working fine