I have a controller in a .NET Core application:
public FriendsController(IFriendRepository friendRepository)
{
this.friendRepository= friendRepository;
}
The IFriendRepository is an interface which is implemented with the class:
public class FriendRepository : IFriendRepository {
...
}
In Startup I set it up by using the following line in ConfigureServices() :
services.AddScoped<IFriendRepository , FriendRepository >();
However, when the controller is used, FriendRepository is has the lifetime set as a singleton instead of scoped. The reason I was able to find was on this page:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1
Under Service lifetimes, Scoped. It shows:
I do not understand how to use Invoke instead of a constructor. The example they use is for a custom middleware, which I at least can't wrap my head on how to interpret it for a constructor.
public class FriendRepository : IFriendRepository
{
private readonly ManagementDbContext dbContext;
public FriendRepository(ManagementDbContext dbContext)
{
this.dbContext = dbContext;
}
public void Add(Friend friend)
{
this.dbContext.Friends.Add(friend);
}
public void Remove(Friend friend)
{
this.dbContext.Remove(friend);
}
public void Update(Friend friend)
{
this.dbContext.Update(friend);
}
}
The following is "GetFriends", inside FriendRepository:
public async Task<QueryResult<Friend>> GetFriendsAsync(FriendQuery queryObj)
{
var result = new QueryResult<Friend>();
var query = dbContext.Friends
.Include(c => c.Type)
.AsQueryable();
if(queryObj.TypeId.HasValue)
{
query = query.Where(c => c.Type.Id == queryObj.TypeId);
}
if(queryObj.Name != null && queryObj.Name.Length > 0)
{
query = query.Where(c => c.Name.Contains(queryObj.Name));
}
// todo add total price here
var columnsMap = new Dictionary<string, Expression<Func<Calculation, object>>>()
{
["id"] = c => c.Id,
["name"] = c => c.Name,
["type"] = c => c.Type,
["totalFriends"] = c => c.TotalFriends,
["createdTime"] = c => c.CreatedTime
};
query = query.ApplyOrdering(queryObj, columnsMap);
result.TotalItems = await query.CountAsync();
query = query.ApplyPaging(queryObj);
result.Items = await query.ToListAsync();
return result;
}
I solved it, I will first explain my assumption, since the fix might be very much limited to my scenario.
I have all of my DBContext used in 3 repositories. They all use async functions however they all contain awaits inside for any of the async functions used inside of them.
The issue seemed to only occur once I started using these repositories as before I was accessing the dbContext directly in the Controller. This made me consider the problems in the link, which I also posted a picture of in the question:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1
Even though it specified middle ware only, I assumed it was worth a chance since I couldn't figure any other problem.
Now as for the actual problem. One of my functions in the UserRepository, GetUser() is an async method, and even though the error seemed to be in the FriendRepository methods, since they were always the ones crashing, it turns out that the GetUser() function was used once in startup under AddJwtBearer without await.
I had assumed that since it had an await inside of it, it would not create a problem. I also had not noticed this was a problem since I was so focused on the other repository. My hope was that maybe I was missing something as simple as the dependency injection through a constructor in middleware switching lifetime regardless of what the lifetime was already set to.
For anyone else in the future, I ended up doing 2 things which allowed me to clearly debug my application step by step.
I created a Logger static class which allows me to save text to file easily. I use this to log functions being used, constructors etc. This let me ensure that I could track the amount of times constructors and functions were called, in what order and which ones would not be reached. Here is the Logger for anyone else:
public static class Logger
{
public static void Log(string text, string fileName)
{
string path = System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "/" + fileName;
bool done = false;
while (!done)
{
done = true;
try
{
FileStream fileStream = null;
fileStream = System.IO.File.Open(path, System.IO.File.Exists(path) ? FileMode.Append : FileMode.OpenOrCreate);
using (StreamWriter fs = new StreamWriter(fileStream))
{
fs.WriteLine(text);
};
fileStream.Close();
}
catch (IOException)
{
done = false;
}
}
}
public static void Log(string text)
{
Log(text, "logger.txt");
}
}
I added a string to the DBContext and whenever I use it in any function I would add the name of the function after the name of the class it is used in. So if my FriendsRepository would use it in a function GetTypes, it would look like:
myDbContext.methodUsing = "FriendsRepository>GetTypes()";
Thank you to #GuruStron for being patient and giving me advice on how to take this step by step, explaining to me that the middleware error idea had no leg to stand on and suggesting to me on how to approach debugging.
Related
I'm trying to handle a number of subscriptions in and Azure.Messaging.SericeBus.
The Docs suggest that I should register my ServiceBusClient, ServiceBusSender and ServiceBusProcessor for DI.
For the latter, it means I need an instance for each subscription, so I have something like this...
services.AddSingleton(provider =>
{
var options = provider.GetService<IOptions<WorkerOptions>>()
.Value;
var client = provider.GetService<ServiceBusClient>();
var subscription = // code to determine the subscription to use
return client.CreateProcessor(options.Topic, subscription);
}
Now I need to instantiate the processors and that's where I come unstuck. In this example I'm using an IServiceProvider but I think I'm going to have the same problem just using DI and constructor injection.
var processor = MyServiceProvider.GetService<ServiceBusProcessor>()!;
How do I get a specific ServiceBusProcessor?
I thought I should be able to "name" each instance but that doesn't appear to be possible.
What am I missing?
With .NET Core DI, you need to use separate types to discern between the injection targets. One way to do this is to create a dedicated class for each subscription, e.g.
public abstract class ProcessorProvider
{
private readonly ServiceBusProcessor _proc;
public ProcessorProvider(ServiceBusProcessor proc)
{
_proc = proc;
}
public virtual ServiceBusProcessor Processor { get => _proc; }
}
public class ProcessorProviderA : ProcessorProvider
{
public ProcessorProviderA(ServiceBusProcessor proc): base(proc) {}
}
public class ProcessorProviderB : ProcessorProvider
{
public ProcessorProviderB(ServiceBusProcessor proc): base(proc) {}
}
In your classes, you do not inject the processor directly, but rely on the different classes that provide the processor, e.g.
public class ClassThatReliesOnSubscriptionA
{
private readonly ServiceBusProcessor _proc;
public ClassThatReliesOnSubscriptionA(ProcessorProviderA procProv)
{
_proc = _procProv.Processor;
}
}
// Same for subscription B
This way, you can add a registration for IProcessorProviderForSubscriptionA and IProcessorProviderForSubscriptionB like this:
services.AddSingleton<ProcessorProviderA>(provider =>
{
var options = provider.GetService<IOptions<WorkerOptions>>()
.Value;
var client = provider.GetService<ServiceBusClient>();
var subscription = // Access subscription A
var proc = client.CreateProcessor(options.Topic, subscription);
return new ProcessorProviderA(proc);
}
services.AddSingleton<ProcessorProviderB>(provider =>
{
var options = provider.GetService<IOptions<WorkerOptions>>()
.Value;
var client = provider.GetService<ServiceBusClient>();
var subscription = // Access subscription B
var proc = client.CreateProcessor(options.Topic, subscription);
return new ProcessorProviderB(proc);
}
This way the inversion of control container can discern between the types that are required by the classes (ClassThatReliesOnSubscriptionA in this sample). Please note that above code is a sample that can give you an outline on how to solve the problem. You can optimize the code further, e.g. by moving common steps into ProcessorProvider. In order to improve "mockability" in unit tests, you could also use marker interfaces instead of the classes.
I am not sure about how such a pattern named or even if it exists, but I named it 'container pattern'.
What I am trying to accomplish: to have an abstraction to hold a list of entities, being able only to add entities, and remove them only when entities saved to the database. I must say it works quite well and I like it much more than passing around List<> like I did earlier.
I just learned that testing private fields is big no-no, but I don't know how I can test Add method alone. Or how to test SaveAndClean without invoking Add. So far testing private field using additional constructor seem clean, but probably there are better solutions.
namespace test
{
class Container
{
private readonly List<Entity> _results;
private readonly IRepostory _repo;
// used for prod
public Container(IRepostory repo)
: this(new List<Entity>(500000), repo)
{
}
// used for tests
internal Container(List<Entity> results, IRepostory repo)
{
_results = results;
_repo = repo;
}
public void Add(Entity entity)
{
_results.Add(entity);
}
public async Task<bool> SaveAndClearAsync()
{
if (!_results.Any())
{
return true;
}
try
{
await _repo.SaveAsync(_results);
_results.Clear();
return true;
}
catch (Exception ex)
{
// logging
}
return false;
}
}
}
[Fact]
public void Add_AddToExisting_EntityAdded()
{
// Arrange
var results = new List<Entity>();
results.Add(new Entity { Name = "md51" });
var repo = new Mock<IRepository>(MockBehavior.Strict);
var service = new Container(results, repo.Object);
var newEntity = new Entity { Name "md52" };
// Act
service.Add(newEntity);
// Assert
Assert.Equal("md51", results[0].Name);
Assert.Equal("md52", results[1].Name);
Assert.Equal(2, results.Count);
}
In your case I would test the behavior as a black box. And from a black box perspective only calling Add doesn't produce any behavior so I'd leave it at that. But calling Add() 2 times and SaveAndClearAsync does, so just test that.
You shouldn't change your code interface for the sole purpose of testing. That's an anti-pattern as well.
I recommend this Dave Farley video on test mistakes.
I have a simple command as per the CQRS pattern as follows:
public sealed class EditPersonalInfoCommandHandler : ICommandHandler<EditPersonalInfoCommand> {
private readonly AppDbContext _context;
public EditPersonalInfoCommandHandler(AppDbContext context) {
_context = context;
}
public Result Handle(EditPersonalInfoCommand command) {
var studentRepo = new StudentRepository(_context);
Student student = studentRepo.GetById(command.Id);
if (student == null) {
return Result.Failure($"No Student found for Id {command.Id}");
}
student.Name = command.Name;
student.Email = command.Email;
_context.SaveChanges();
return Result.Success();
}
}
Now I have a requirement to attempt _context.SaveChanges() upto 5 times if it fails with an exception. For this I can simply have a for loop in the method as:
for(int i = 0; i < 5; i++) {
try {
//required logic
} catch(SomeDatabaseException e) {
if(i == 4) {
throw;
}
}
}
The requirement is to execute the method as a single unit. The thing is that once the _context.SaveChanges() throws an exception, the same _context cannot be used to reattempt the logic. The docs say:
Discard the current DbContext.
Create a new DbContext and restore the state of your application from the database.
Inform the user that the last operation might not have been completed successfully.
However, in the Startup.cs, I have the AppDbContext as a scoped dependency. In order to reattempt the method logic I require a new instance of AppDbContext but being registered as scoped will not allow that.
One solution that comes to my mind is to make the AppDbContext transient. But I have a feeling that by doing that I will open whole set of new problems for myself. Can anyone help me with it?
There are at least too kinds of error while saving the context. The first occurs during the command execution. The second occurs during committing (which much more rarely happens).
The second error may happen even when the data has been updated successfully. So your code just handles the first kind of error but does not take the second kind into account.
For the first kind of error, you can inject into your command handler a DbContext factory or use IServiceProvider directly. It's kind of anti-pattern but in this case we have no choice, like this:
readonly IServiceProvider _serviceProvider;
public EditPersonalInfoCommandHandler(IServiceProvider serviceProvider) {
_serviceProvider = serviceProvider;
}
for(int i = 0; i < 5; i++) {
try {
using var dbContext = _serviceProvider.GetRequiredService<AppDbContext>();
//consume the dbContext
//required logic
} catch(SomeDatabaseException e) {
if(i == 4) {
throw;
}
}
}
However as I said, to handle both kind of errors, we should use the so-called IExecutionStrategy in EFCore. There are several options as introduced here. But I think the following would suit your scenario best:
public Result Handle(EditPersonalInfoCommand command) {
var strategy = _context.Database.CreateExecutionStrategy();
var studentRepo = new StudentRepository(_context);
Student student = studentRepo.GetById(command.Id);
if (student == null) {
return Result.Failure($"No Student found for Id {command.Id}");
}
student.Name = command.Name;
student.Email = command.Email;
const int maxRetries = 5;
int retries = 0;
strategy.ExecuteInTransaction(_context,
context => {
if(++retries > maxRetries) {
//you need to define your custom exception to be used here
throw new CustomException(...);
}
context.SaveChanges(acceptAllChangesOnSuccess: false);
},
context => context.Students.AsNoTracking()
.Any(e => e.Id == command.Id &&
e.Name == command.Name &&
e.Email == command.Email));
_context.ChangeTracker.AcceptAllChanges();
return Result.Success();
}
Note that I suppose your context exposes a DbSet<Student> via the property Students.
If you have any other error not related to connection, it will not be handled by the IExecutionStrategy and that makes a lot of sense. Because that's when you need to fix the logic, retrying thousands of times won't help and always ends up in that error. That's why we don't need to care about the detailed originally thrown Exception (which is not exposed when we use IExecutionStrategy). Instead we use a custom Exception (as commented in my code above) to just notify a failure of saving the changes due to some connection-related issue.
I am writing some unit tests for a method that uploads a file using SSH.Net.
The project is a WPF app and uses Caliburn.Micro as MVVM framework and also to inject the following object in the constructor of the class I am testing:
private IFileTransferManager _fileTransferManager;
public FileUploadViewModel(IFileTransferManager fileTransferManager) : base(eventAggregator)
{
_fileTransferManager = fileTransferManager;
}
In the test project I am mocking IFileTransferManager:
private Mock<IFileTransferManager> _fileTransferManager = new Mock<IFileTransferManager>();
But now I got to the point, when in code I need to ask for a new instance of IFileTransferManager from IoC container, IoC being a static class in Caliburn.Micro:
_fileTransferManager = IoC.Get<IFileTransferManager>();
await _fileTransferManager.UploadFile(connection, file.FullName, destinationPath).ConfigureAwait(false);
How can I refactor the above code to make it testable, because currently it throws System.InvalidOperationException in Caliburn.Micro.dll due to the fact that I am re-instantiating _fileTransferManager?
I would probably do something like this, assuming there are other limiting factors that mean you want to change as little outward detail about the class as possible (note: I haven't tested this so may have to tweak a little)
public class ClassIAmTesting
{
//Have a Func to fetch a file manager...
private Func<IFileTransferManager> _filemgr = null;
//Have a property which we'll use in this class to get the File manager
public Func<IFilterTransferManager> GetFileManager
{
get
{
//If we try to use this property for the first time and it's not set,
//then set it to the default implementation.
if (_fileMgr == null)
{
_fileMgr = () => IoC.Get<IFileTransferManager>();
}
return _fileMgr;
}
set
{
//allow setting of the function which returns an IFileTransferManager
if (_fileMgr == null)
{
_fileMgr = value;
}
}
}
//this is the method you ultimately want to test...
public async Task<bool> SomeMethodIAmTesting()
{
//don't do this any more:
//_fileTransferManager = IoC.Get<IFileTransferManager>();
//instead do this.
_fileTransferManager = GetFileManager();
await _fileTransferManager
.UploadFile(connection, file.FullName, destinationPath)
.ConfigureAwait(false);
return true;
}
}
Then in your testing:
Mock<IFileTransferManager> _fileTransferManager = new Mock<IFileTransferManager>();
var cut = new ClassIAmTesting();
//not used Moq for a long time, but think you have to access .Object to get to the
//actual implementation of IFileTransferManager?
cut.GetFileManager = () => _fileTransferManager.Object;
//Do actual tests..
var result = cut.SomeMethodIAmTesting();
//Do assertions...
I suggest this approach because:
It provides a way of overriding the way the class gets the IFileTransferManager for testing
It 'falls back' to the default implementation if this override is not used, preserving the original behaviour - you don't need to change existing calls to this class at all from non-testing code
It does not change the Constructor or add a new one, which I assume is a problem since you don't simply inject an instance of the IFileTransferManager in.
one improvement might be to make the set internal which would prevent other projects from setting this method, and it could then be exposed via InternalVisibleTo or similar, but I'm trying to keep the scope fairly tight...
Inject a factory using a Func<TResult> delegate.
private readonly Func<IFileTransferManager> fileTransferManagerFactory;
public FileUploadViewModel(Func<IFileTransferManager> fileTransferManagerFactory) : base(eventAggregator) {
this.fileTransferManagerFactory = fileTransferManagerFactory;
}
This would allow for as many instances as needed being created when uploading
//get an instance using factory delegate
var fileTransferManager = fileTransferManagerFactory();
await fileTransferManager.UploadFile(connection, file.FullName, destinationPath).ConfigureAwait(false); IoC.Get<IFileTransferManager>();
For unit testing a function can be easily created to provid as many mocks needed for the test case
I have a LogContext Model :
using System.Data.Entity;
namespace Logging.Models
{
public class LogContext : DbContext
{
// You can add custom code to this file. Changes will not be overwritten.
//
// If you want Entity Framework to drop and regenerate your database
// automatically whenever you change your model schema, add the following
// code to the Application_Start method in your Global.asax file.
// Note: this will destroy and re-create your database with every model change.
//
// System.Data.Entity.Database.SetInitializer(new System.Data.Entity.DropCreateDatabaseIfModelChanges<Logging.Models.ProductContext>());
public LogContext() : base("name=LogContext")
{
Database.SetInitializer<LogContext>(null);
}
public DbSet<Log> Logs { get; set; }
}
}
but when I try to reference the Logs in my other LogContext class under App_code I'm getting an error trying to reference the context.Logs.Load();
"cannot be accessed with an instance reference; qualify it with a type name"
How do I reference and render all the rows in my table? What am i doing wrong?
Thanks
using System;
using System.Collections.Generic;
using System.Linq;
using Logging.Controllers;
using Logging.Models;
namespace Logging
{
public class LogContext : IDisposable
{
private static readonly List<Log> Logs = new List<Log>();
static LogContext()
{
using (var context = new LogContext())
{
**context.Logs.Load();**
}
//Logs.Add(new Log() { Id = 1, LoggerName = "TESTSYS1", InnerException = "InnerException", LogText = "LogText", ThreadID = 1, StackTrace = "Stack Trace", eLevel = "INFO" });
//Logs.Add(new Log() { Id = 2, LoggerName = "TESTSYS2", InnerException = "InnerException", LogText = "LogText", ThreadID = 2, StackTrace = "Stack Trace", eLevel = "ERROR" });
//Logs.Add(new Log() { Id = 3, LoggerName = "TESTSYS3", InnerException = "InnerException", LogText = "LogText", ThreadID = 3, StackTrace = "Stack Trace", eLevel = "WARN" });
}
void IDisposable.Dispose()
{
}
public void GetLoggies()
{
using (var context = new LogContext())
{
foreach (var log in context.GetLogs())
{
Logs.Add(log);
}
}
}
public Log GetLog(int id)
{
var log = Logs.Find(p => p.Id == id);
return log;
}
public IEnumerable<Log> GetLogs()
{
return LogContext.Logs;
}
public Log AddLog(Log p)
{
Logs.Add(p);
return p;
}
public void Delete(int id)
{
var product = Logs.FirstOrDefault(p => p.Id == id);
if (product != null)
{
Logs.Remove(product);
}
}
public bool Update(int id, Log log)
{
Log rLog = Logs.FirstOrDefault(p => p.Id == id);
if (rLog != null)
{
rLog = log;
return true;
}
return false;
}
}
}
The problem is frankly very bad design.
Your class here has the same name as your context and also has a member with the same name as a member on your context, i.e. Logs. This is a case study in how intelligent the compiler is, in that the only reason the whole thing doesn't explode, is because it's able to make some sense out of which you want in which place, given context. Still, it might guess wrong, and you will certainly get confused at some point. If you insist on maintaining it this way, you should fully-qualify all uses of your actual context class, i.e. new Namespace.To.LogContext(), so the compiler isn't just guessing.
Using using around a context is a hugely bad idea. A context instance should ideally be request-scoped. Among other things, the context employs change tracking, and when you start passing entities between different context instances, you're going to run headlong into a brick wall. Instead, you should inject your context into this class and save it as a field on the class.
Implementing IDisposable is not something you should do lightly. There's a very particular way it needs to be implemented or you're actually causing more harm than good.
public class Base: IDisposable
{
private bool disposed = false;
//Implement IDisposable.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
// Set large fields to null.
disposed = true;
}
}
// Use C# destructor syntax for finalization code.
~Base()
{
// Simply call Dispose(false).
Dispose (false);
}
}
See: https://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.100).aspx
However, if you inject your context, this class will no longer own the context, and therefore wouldn't need to even implement IDisposable. And, for the love of everything good and holy, don't implement IDisposable when you're injecting dependencies. I see far too many developers do this and end up with strange bugs because resources are being disposed incorrectly.
Finally, just throw this class away completely. What you're essentially trying to create here (incorrectly) is a repository, and you don't need that. Entity Framework already implements the repository and unit of work patterns. As you can see from your methods here, all you're doing is basically proxying from your method to a nearly equivalent method on the DbSet. You're buying yourself nothing but just an additional layer that now has to be maintained, more entropy for your application code, and technical debt. For a more detail description of why this is the wrong approach see: https://softwareengineering.stackexchange.com/a/220126/65618