I've 'successfully' written a CodeFix and FixAllProvider, BUT...
The diagnostic I'm trying to handle can occur multiple times in the same document on the same line. However, the behavior under unit test (CSharpCodeFixTest) stumps me.
If a test generates only one instance of the diagnostic, CSharpCodeFix<> calls the CodeFix initially then calls the FixAllProvider multiple times during Verification. The test succeeds.
If a test generates more than one diagnostic, CSharpCodeFix<> calls the CodeFix once. CSharpCodeFix<> never calls the FixAllProvider, and since the CodeFix cannot fix all instances. the test fails the before/after document comparison.
Note that in these samples, namespaces (not shown) disambiguate the classes from their bases. I've removed the fix implementations because I believe them irrelevant to the problem.
First the CodeFix
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CodeFixProvider)), Shared]
public class CodeFixProvider : Microsoft.CodeAnalysis.CodeFixes.CodeFixProvider
{
public sealed override ImmutableArray<string> FixableDiagnosticIds
{
get { return ImmutableArray.Create(EGNT0003NoInlineInstantiationAnalyzer.DiagnosticId); }
}
public sealed override Microsoft.CodeAnalysis.CodeFixes.FixAllProvider GetFixAllProvider()
{
Microsoft.CodeAnalysis.CodeFixes.FixAllProvider provider = FixAllProvider.Instance;
return provider;
}
public static readonly string EquivalenceKey = "EG0003CodeFixProvider";
public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
{
foreach (Diagnostic diagnostic in context.Diagnostics.Where(d => FixableDiagnosticIds.Contains(d.Id)))
{
context.RegisterCodeFix(CodeAction.Create(title: "Introduce local variable",
token => GetTransformedDocumentAsync(context.Document, diagnostic, token),
equivalenceKey: EquivalenceKey), diagnostic);
}
return Task.CompletedTask;
}
;
Here is the FixAllProvider
public sealed class FixAllProvider : Microsoft.CodeAnalysis.CodeFixes.FixAllProvider
{
private FixAllProvider()
{
}
private static readonly Lazy<FixAllProvider> lazy = new Lazy<FixAllProvider>(() => new FixAllProvider());
public static FixAllProvider Instance
{
get
{
return lazy.Value;
}
}
public override IEnumerable<string> GetSupportedFixAllDiagnosticIds(Microsoft.CodeAnalysis.CodeFixes.CodeFixProvider originalCodeFixProvider)
{
string[] diagnosticIds = new[]
{
EGNT0003NoInlineInstantiationAnalyzer.DiagnosticId,
};
return diagnosticIds;
}
public override async Task<CodeAction> GetFixAsync(FixAllContext fixAllContext)
{
:
Finally here is the CodeAction invoked by the FixAllProvider.
public class FixAllCodeAction : CodeAction
{
private readonly List<KeyValuePair<Document, ImmutableArray<Diagnostic>>> _diagnosticsToFix;
private readonly Solution _solution;
public FixAllCodeAction(string title, Solution solution, List<KeyValuePair<Document, ImmutableArray<Diagnostic>>> diagnosticsToFix)
{
this.Title = title;
_solution = solution;
_diagnosticsToFix = diagnosticsToFix;
}
public override string Title { get; }
public override string EquivalenceKey => "EG0003CodeFixProvider";
protected override async Task<Solution> GetChangedSolutionAsync(CancellationToken cancellationToken)
{
Solution newSolution = _solution;
:
I've debugged through CSharpCodeFixTest<> and continue to do so. I'm hoping someone has seen this issue before and can see my mistake.
I expected to see the code fix tests to complete successfully. I verified through other means that the documents produced by the CodeFix and the FixAllProvider are valid and correct.
Related
Suppose I have 2 (or more) types of objects that the user can control:
public class Runner : MonoBehaviour
{
//...
public void Run() { //... }
}
and
public class Jumper : Runner
{
//...
public void Jump() { //... }
}
Furthermore, we have the following InputActionMaps in our InputActionAsset:
runner action map
jumper action map
My current solution defines the control-to-action mappings using separate "Controls" classes.
Controls.cs:
public abstract class Controls<T>
{
protected T controlled;
public Controls(InputActionMap actionMap, T controlled)
{
SetupInputCallbacks(actionMap);
this.controlled = controlled;
}
protected abstract void SetupInputCallbacks(InputActionMap actionMap);
}
RunnerControls.cs
public class RunnerControls : Controls<Runner>
{
public RunnerControls(InputActionMap actionMap, Runner controlled)
: base(actionMap, controlled) { }
protected override void SetupInputCallbacks(InputActionMap actionMap)
{
InputAction runAction = actionMap.FindAction("Run");
runAction.perform += controlled.Run();
}
}
Jumper.cs
public class JumperControls : Controls<Jumper>
{
public JumperControls(InputActionMap actionMap, Runner controlled)
: base(actionMap, controlled) { }
protected override void SetupInputCallbacks(InputActionMap actionMap)
{
InputAction runAction = actionMap.FindAction("Run");
runAction.perform += controlled.Run();
InputAction jumpAction = actionMap.FindAction("Jump");
jumpAction.perform += controlled.Jump();
}
}
The code for the "run action" is duplicated, and although this may seem minor here, my actual code does this to a much greater extent. I tried something like public class JumperControls : RunnerControls, but then the controlled.Jump() would fail since the T in the Controls class evaluates to Runner. If anyone can help me come up with a solution to this that'd be a huge help, even if that means changing the architecture. Thanks!
You can make Runner and Jumper separate interfaces with their respective Run and Jump methods. The actual monobehaviours will be implementing the interfaces and having their own Run and Jump logic. So in the Controls<T> you can check whether the T implements the respective interface:
public class Controls<T>
{
protected T controlled;
public Controls(InputActionMap actionMap, T controlled)
{
SetupInputCallbacks(actionMap);
this.controlled = controlled;
}
protected virtual void SetupInputCallbacks(InputActionMap actionMap)
{
if (T is Runner) ....
if (T is Jumper) ....
}
}
In my application, I have a service that requires a constructor parameter not resolved by Autofac, that I instantiate using a delegate factory:
public class Service
{
public Service(string parameter /*, ... other dependencies */)
{
}
public delegate Service Factory(string parameter);
}
This works great! I really love this feature.
I also like the Controlled Lifetime relationship, so I can let my component depend on a Func<Owned<ISomething>> like this:
public class Component
{
private Func<Owned<ISomething>> _somethingFactory;
/* constructor omitted for brevity */
public void DoSomethingUseful()
{
using (var ownedSomething = _somethingFactory())
{
/* Lots of useful code here */
}
}
}
My problem is that now I want to combine the two. I can't have an instance of Func<Owned<Service>> injected, because it needs that parameter, so my current solution is to abstract the factory away into another service, say IServiceFactory:
public interface IServiceFactory
{
Service Create(string parameter);
}
...implemented as such:
public class ServiceFactory : IServiceFactory
{
private Service.Factory _internalFactory;
public ServiceFactory(Service.Factory internalFactory)
{
_internalFactory = internalFactory;
}
public Service Create(string parameter)
{
return _internalFactory(parameter);
}
}
My component then becomes this:
public class Component
{
Func<Owned<IServiceFactory>> _serviceFactoryFactory;
/* ... */
}
The need for such a field name leaves a bad taste in my mouth to the point that I suspect there must be a cleaner way to handle this case.
Is there another way?
You could change your injected factory to include the string parameter:
private Func<string, Owned<ISomething>> _somethingFactory;
Then you can pass the string to the factory when you want to create a new instance:
public void DoSomethingUseful()
{
using (var ownedSomething = _somethingFactory("my parameter"))
{
/* Lots of useful code here */
}
}
I've created a .NET Fiddle with a small working sample.
My database have different schema depending on user selections on runtime.
My code is below:
public partial class FashionContext : DbContext
{
private string _schema;
public FashionContext(string schema) : base()
{
_schema = schema;
}
public virtual DbSet<Style> Styles { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlServer(#"Server=.\sqlexpress;Database=inforfashionplm;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Style>()
.ToTable("Style", schema: _schema);
}
}
Upon testing. I created a context instance with 'schema1'.
So far so good.
But when I create another context instance with different schema 'schema2', the resulting data in which the schema is still on 'schema1'.
Here is the implementation:
using (var db = new FashionContext("schema1"))
{
foreach (var style in db.Styles)
{
Console.WriteLine(style.Name);
}
}
Console.ReadLine();
Console.Clear();
using (var db = new FashionContext("schema2"))
{
foreach (var style in db.Styles)
{
Console.WriteLine(style.Name);
}
}
Console.ReadLine();
Later I noticed that the OnModelCreating is called only one time, so it is never called again when you create a new context instance of the same connection string.
Is it possible to have dynamic schema on runtime? Note: this is possible in EF6
One of possible way was mentioned above, but briefly, so I will try to explain with examples.
You ought to override default ModelCacheKeyFactory and ModelCacheKey.
ModelCachekeyFactory.cs
internal sealed class CustomModelCacheKeyFactory<TContext> : ModelCacheKeyFactory
where TContext : TenantDbContext<TContext>
{
public override object Create(DbContext context)
{
return new CustomModelCacheKey<TContext>(context);
}
public CustomModelCacheKeyFactory([NotNull] ModelCacheKeyFactoryDependencies dependencies) : base(dependencies)
{
}
}
ModelCacheKey.cs, please review Equals and GetHashCode overridden methods, they are not best one and should be improved.
internal sealed class ModelCacheKey<TContext> : ModelCacheKey where TContext : TenantDbContext<TContext>
{
private readonly string _schema;
public ModelCacheKey(DbContext context) : base(context)
{
_schema = (context as TContext)?.Schema;
}
protected override bool Equals(ModelCacheKey other)
{
return base.Equals(other) && (other as ModelCacheKey<TContext>)?._schema == _schema;
}
public override int GetHashCode()
{
var hashCode = base.GetHashCode();
if (_schema != null)
{
hashCode ^= _schema.GetHashCode();
}
return hashCode;
}
}
Register in DI.
builder.UseSqlServer(dbConfiguration.Connection)
.ReplaceService<IModelCacheKeyFactory, CustomModelCacheKeyFactory<CustomContext>>();
Context sample.
public sealed class CustomContext : TenantDbContext<CustomContext>
{
public CustomContext(DbContextOptions<CustomContext> options, string schema) : base(options, schema)
{
}
}
You can build the model externally and pass it into the DbContext using DbContextOptionsBuilder.UseModel()
Another (more advanced) alternative is to replace the IModelCacheKeyFactory to take schema into account.
I found a way to recreate the compiled model on each context creation.
public partial class MyModel : DbContext {
private static DbConnection _connection
{
get
{
//return a new db connection
}
}
private static DbCompiledModel _model
{
get
{
return CreateModel("schema name");
}
}
public MyModel()
: base(_connection, _model, false)
{
}
private static DbCompiledModel CreateModel(string schema)
{
var modelBuilder = new DbModelBuilder();
modelBuilder.HasDefaultSchema(schema);
modelBuilder.Entity<entity1>().ToTable(schema + ".entity1");
var builtModel = modelBuilder.Build(_connection);
return builtModel.Compile();
}
}
I have an aggregate root with a few events and commands. One of those commands is a CreateCommand. That command should create a new aggregate root with a given ID. Every other event/command should just update an existing aggregate root and fail if the aggregate root with the given ID doesn't exist.
How can I make Cirqus work this way?
This is how I configure my CommandProcessor:
var commandProcessor = CommandProcessor
.With()
#if DEBUG
.Logging(l =>
{
if (_useConsoleForLogging)
{
l.UseConsole(Logger.Level.Debug);
}
else
{
l.UseDebug(Logger.Level.Debug);
}
})
#endif
.EventStore(e => e.UseSqlServer(_connectionString, _eventsTableName))
.EventDispatcher(e => e.UseViewManagerEventDispatcher(viewManagers))
.Create();
This is the CreateCommand:
public class CreateCommand : ExecutableCommand
{
public CreateCommand()
{
CreatedGuid = Guid.NewGuid();
}
public Guid CreatedGuid { get; }
public override void Execute(ICommandContext context)
{
var root = context.Create<MyAggregateRoot>(CreatedGuid.ToString());
}
}
Of course this CreateCommand contains more code that emits a few events to immediately update some properties of the created instance, but I've removed them as they're not vital to this question.
You can do that by using ExecutableCommand to implement your own update command - you could call it UpdateCommand.
It could look something like this:
public abstract class UpdateCommand<TAggregateRoot>
{
readonly string _aggregateRootId;
protected UpdateCommand(string aggregateRootId)
{
_aggregateRootId = aggregateRootId;
}
public override void Execute(ICommandContext context)
{
var instance = context.Load<TAggregateRoot>(_aggregateRootId);
Update(instance);
}
public abstract void Update(TAggregateRoot instance);
}
and then all commands derived off of UpdateCommand would experience exceptions if they tried to address non-existing instances.
Similarly, you could ensure creation with a CreateCommand base class that would use ICommandContext's Create<TAggregateRoot> method to ensure that an existing instance was not accidentally being addressed.
I'm using SpecFlow with Nunit and I'm trying to setup my enviroment tests using TestFixtureSetUpAttribute, but it's never called.
I already tried to use MSTests and ClassInitialize attribute, but the same happen. The function isn't called.
Any ideas Why?
[Binding]
public class UsersCRUDSteps
{
[NUnit.Framework.TestFixtureSetUpAttribute()]
public virtual void TestInitialize()
{
// THIS FUNCTION IS NEVER CALLER
ObjectFactory.Initialize(x =>
{
x.For<IDateTimeService>().Use<DateTimeService>();
});
throw new Exception("BBB");
}
private string username, password;
[Given(#"I have entered username ""(.*)"" and password ""(.*)""")]
public void GivenIHaveEnteredUsernameAndPassword(string username, string password)
{
this.username = username;
this.password = password;
}
[When(#"I press register")]
public void WhenIPressRegister()
{
}
[Then(#"the result should be default account created")]
public void ThenTheResultShouldBeDefaultAccountCreated()
{
}
Solution:
[Binding]
public class UsersCRUDSteps
{
[BeforeFeature]
public static void TestInitialize()
{
// THIS FUNCTION IS NEVER CALLER
ObjectFactory.Initialize(x =>
{
x.For<IDateTimeService>().Use<DateTimeService>();
});
throw new Exception("BBB");
}
private string username, password;
[Given(#"I have entered username ""(.*)"" and password ""(.*)""")]
public void GivenIHaveEnteredUsernameAndPassword(string username, string password)
{
this.username = username;
this.password = password;
}
[When(#"I press register")]
public void WhenIPressRegister()
{
}
[Then(#"the result should be default account created")]
public void ThenTheResultShouldBeDefaultAccountCreated()
{
}
Your TestInitialize is not called because it is inside your Steps class and not inside in an Unit Tests (because the actual unit test is inside the .cs which is generated from your .feature file).
SpecFlow has it's own test-lifetime events which are called hooks, these are all the predefined hooks:
[BeforeTestRun] / [AfterTestRun]
[BeforeFeature] / [AfterFeature]
[BeforeScenario] / [AfterScenario]
[BeforeScenarioBlock] / [AfterScenarioBlock]
[BeforeStep] / [AfterStep]
Note that this allows for greater flexibility in setup. For additional information see the documentation.
Based on the fact that you want to use the TestFixtureSetUp attribute you will probably need the BeforeFeature hook which will be called once before each feature, so you need to write:
[Binding]
public class UsersCRUDSteps
{
[BeforeFeature]
public static void TestInitialize()
{
ObjectFactory.Initialize(x =>
{
x.For<IDateTimeService>().Use<DateTimeService>();
});
throw new Exception("BBB");
}
//...
}
Note that the [BeforeFeature] attribute needs a static method.
You should also note that if you are using the VS integration there is an project item type called SpecFlow Hooks (event bindings) which creates a binding class with some predefined hooks to help you get started.