As per this tutorial on asp.net, it shows this code:
using System;
using ContosoUniversity.Models;
namespace ContosoUniversity.DAL
{
public class UnitOfWork : IDisposable
{
private SchoolContext context = new SchoolContext();
private GenericRepository<Department> departmentRepository;
private GenericRepository<Course> courseRepository;
public GenericRepository<Department> DepartmentRepository
{
get
{
if (this.departmentRepository == null)
{
this.departmentRepository = new GenericRepository<Department>(context);
}
return departmentRepository;
}
}
public GenericRepository<Course> CourseRepository
{
get
{
if (this.courseRepository == null)
{
this.courseRepository = new GenericRepository<Course>(context);
}
return courseRepository;
}
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
Do I have to write code every time I want add a new database table? For instance, if I wanted to add a StudentsRepository, I would have to do this (?):
private GenericRepository<Student> studentRepository;
public GenericRepository<Student> StudentRepository
{
get
{
if (this.studentRepository == null)
{
this.studentRepository = new GenericRepository<Student>(context);
}
return studentRepository;
}
}
What if my database has 50 tables? Do I have to write this code for all 50!?
The answer to your question is "yes", the unit of work should contain properties to access all possible repositories.
If it bothers you to write code, create a T4 template and let the class be generated automatically.
Related
I have the following structure below.
Questions:
Is IStrategy interface needed at all? Because I've seen people doing same thing I did - there is a Start method which is defined as an abstract in the base class and they exposed it with an interface which defines it as well. However, other people think that it is enough to specify the Start method only in the base class and the interface is not needed at all, because the code gets more complicated. What's your opinion?
I'm defining IBinanceClient and IBinanceSocketClient in the base class and they both have to be disposed at some point. In my code below, I implemented the IDisposable in the derived class, but however, I think it's a better decision to move it in the base class, because BinanceClient is defined there. What do you think?
public interface IStrategy
{
public void Start(Bot bot, CancellationToken token);
}
public abstract class StrategyBase : IStrategy
{
public IBinanceClient Client { get; }
public IBinanceSocketClient SocketClient { get; }
protected StrategyBase(string apiKey, string secretKey)
{
Client = new BinanceClient(new BinanceClientOptions()
{
ApiCredentials = new ApiCredentials(apiKey, secretKey),
AutoTimestamp = true,
AutoTimestampRecalculationInterval = TimeSpan.FromMinutes(30)
});
SocketClient = new BinanceSocketClient(new BinanceSocketClientOptions()
{
ApiCredentials = new ApiCredentials(apiKey, secretKey),
AutoReconnect = true,
ReconnectInterval = TimeSpan.FromMinutes(1)
});
}
public List<BinanceStreamTick> Tickers { get; set; }
// Methods that all strategies use
public void GetTickers()
{
... implementation
}
public abstract void Start(Bot bot, CancellationToken token); // ???
}
public class CompositeStrategy : StrategyBase, IDisposable
{
public CompositeStrategy(string apiKey, string secretKey) : base(apiKey, secretKey)
{
}
public override void Start(Bot bot, CancellationToken token)
{
... implementation
}
private bool _disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
if (Client != null)
Client.Dispose();
if (SocketClient != null)
{
SocketClient.UnsubscribeAll();
SocketClient.Dispose();
}
}
_disposed = true;
}
}
Edit:
Other way, based on #Wiktor Zychla's comment.
public interface IStrategy
{
public void Start(Bot bot, CancellationToken token);
}
public abstract class StrategyBase : IStrategy, IDisposable
{
public IBinanceClient Client { get; }
public IBinanceSocketClient SocketClient { get; }
protected StrategyBase(string apiKey, string secretKey)
{
Client = new BinanceClient(new BinanceClientOptions()
{
ApiCredentials = new ApiCredentials(apiKey, secretKey),
AutoTimestamp = true,
AutoTimestampRecalculationInterval = TimeSpan.FromMinutes(30)
});
SocketClient = new BinanceSocketClient(new BinanceSocketClientOptions()
{
ApiCredentials = new ApiCredentials(apiKey, secretKey),
AutoReconnect = true,
ReconnectInterval = TimeSpan.FromMinutes(1)
});
}
public List<BinanceStreamTick> Tickers { get; set; }
public void GetTickers()
{
... implementation
}
public abstract void Start(Bot bot, CancellationToken token);
private bool _disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
if (Client != null)
Client.Dispose();
if (SocketClient != null)
{
SocketClient.UnsubscribeAll();
SocketClient.Dispose();
}
}
_disposed = true;
}
}
public class CompositeStrategy : StrategyBase
{
public CompositeStrategy(string apiKey, string secretKey) : base(apiKey, secretKey)
{
}
public override void Start(Bot bot, CancellationToken token)
{
... implementation
}
}
Whether you need the IStrategy interface or not depends on the context where you are using this, so is not clear. However, having IStrategy with a Start () method and StrategyBase with an abstract Start() method seems like duplication, which would suggest you only need the base class.
Regarding where to put the Dispose(), the general rule is objects should be disposed in the same class where they are created. (In the same method, if possible, but that's only for very short-lived objects and not the case here.)
You don't show where SocketClient and Client are created, but they are declared in StrategyBase, which would suggest that is where they should be disposed.
I have implemented this Windows Service which sends emails using SendAsync method, every 30 seconds in batches of 20. I'm using EF6 and SQL Server 2016. Here is some parts of the codes
EmailRepository.cs
public class EmailRepository : IEmailRepository
{
private BBEntities db = null;
public EmailRepository(BBEntities db)
{
this.db = db;
}
public IEnumerable<tb_Email> SelectAll(int batchAge, int batchSize)
{
DateTime tDate = DateTime.Now.AddMinutes(batchAge);
return db.tb_Email.Where(x => x.ReadyToSend.Equals(true) & x.DateSent.Equals(null) & x.DateCreated >= tDate).OrderBy(x => x.DateCreated).Take(batchSize);
}
public tb_Email SelectByID(Guid id)
{
return db.tb_Email.Find(id);
}
public void Update(tb_Email obj)
{
db.Entry(obj).State = EntityState.Modified;
}
#region IDisposable Support
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
db.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
UnitOfWork.cs
public class UnitOfWork : IUnitOfWork
{
private readonly BBEntities ctx = new BBEntities();
private IEmailRepository emailRepository;
public IEmailRepository EmailRepository
{
get
{
if (this.emailRepository == null)
{
this.emailRepository = new EmailRepository(ctx);
}
return emailRepository;
}
}
public void Dispose()
{
this.ctx.Dispose();
}
public void Commit()
{
this.ctx.SaveChanges();
}
}
EmailService.cs
public class EmailService : IEmailService
{
private IUnitOfWork unitOfWork;
public EmailService()
{
unitOfWork = new UnitOfWork();
}
public List<tb_Email> SelectAll(int batchAge, int batchSize)
{
return unitOfWork.EmailRepository.SelectAll(batchAge, batchSize).ToList();
}
public tb_Email SelectByID(Guid id)
{
return unitOfWork.EmailRepository.SelectByID(id);
}
public void Update(tb_Email obj)
{
using (unitOfWork = new UnitOfWork())
{
unitOfWork.EmailRepository.Update(obj);
unitOfWork.Commit();
}
}
}
SMTPService.cs
public class SMTPService : ISMTPService
{
SmtpClient client;
MailMessage newMessage;
EmailService emailService;
IEventLoggerService MailCheckerLog;
public SMTPService()
{
emailService = new EmailService();
MailCheckerLog = new EventLoggerService();
}
public void SendEmail(tb_Email email)
{
try
{// rest of the code .....
newMessage = new MailMessage();
newMessage.Headers.Add("X-Email_Id", email.Id.ToString());
client.SendCompleted += (sender, e) => SendCompletedCallback(sender, e);
tb_Email userState = email;
//
// if I put the update database logic here, it works fine
//
client.SendAsync(newMessage, userState);
}
catch (Exception e)
{
MailCheckerLog.log("Error in SendComplete event handler - Exception: " + e.Message.ToString() + " -- InnerException: " + e.InnerException.Message, EventLogEntryType.Error);
client.Dispose();
newMessage.Dispose();
throw;
}
}
void SendCompletedCallback(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
tb_Email email = (tb_Email)e.UserState;
Console.WriteLine("----------------------------------" + emailID.Id);
email.ReadyToSend = false;
emailService.Update(email);
client.Dispose();
newMessage.Dispose();
}
}
The problem:
So to send and process emails I run SendEmail method in a simple loop with a list of tb_Email objects, once each email is sent I have to update the database.
To do that, I use
email.ReadyToSend = false;
emailService.Update(email);
in my SendCompleted event, as I'm using SendAsync the system goes ahead and process many emails however the SendCompleted event might fire a bit later for each email.
To make sure it is using a unique and single dbContext I am using a using statement on my UoW instance for the update method. This works fine if I put my update logic in SendEmail method directly (which doesn't make any sense as I need to know if the email was sent successfully or not), however If I put it in the event after a few successful updates, it just throw
System.Data.Entity.Core.EntityException: 'The underlying provider failed on Open.'
I don't understand how is it possible when I'm actually creating a new context for each operation.
Sorry I have to answer it myself, the problem was that the UoW variable was still being used by other threads, so the solution is to declare a new variable for the using statement inside the update method, like below
public class EmailService : IEmailService
{
private IUnitOfWork unitOfWork;
public EmailService()
{
unitOfWork = new UnitOfWork();
}
public List<tb_Email> SelectAll(int batchAge, int batchSize)
{
return unitOfWork.EmailRepository.SelectAll(batchAge, batchSize).ToList();
}
public tb_Email SelectByID(Guid id)
{
return unitOfWork.EmailRepository.SelectByID(id);
}
public void Update(tb_Email obj)
{
IUnitOfWork unitOfWorkUpdate;
using (unitOfWorkUpdate = new UnitOfWork())
{
unitOfWorkUpdate.EmailRepository.Update(obj);
unitOfWorkUpdate.Commit();
}
}
}
I have a question about disposing objects.
Consider this IDisposable class
public class MyClass : DisposableParentClass
{
private MyProp _prop;
public MyClass(MyProp prop)
{
_prop = prop;
}
public MyClass()
{
_prop = new MyProp();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_prop.Dispose();
}
base.Dispose(disposing);
}
}
On the first constructor, MyProp is injected. So MyClass is not the owner of the object. But on the second constructor, MyProp is created locally.
Should I always dispose MyProp, or should I check first if it is injected or not.
public class MyClass : DisposableParentClass
{
private MyProp _prop;
private bool _myPropInjected = false;
public MyClass(MyProp prop)
{
_prop = prop;
_myPropInjected = true;
}
public MyClass()
{
_prop = new MyProp();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (!_myPropInjected) { _prop.Dispose(); }
}
base.Dispose(disposing);
}
}
If your class should handle these two situations:
It is not the owner of the provided object, it should not dispose of it
It is the owner of the created object, it should dispose of it
Then yes, you need to have a mechanism that tells these two situations apart.
A common method (common to me anyway) is to use naming convention like this:
private MyProp _prop;
private bool _ownsProp = false;
ie. reverse the meaning of your flags, but this is details, your solution is just fine, and yes, you need to have a solution like this.
If you have a ton of these fields, where each must have its own bool field to handle this, it might be worth creating a helper class, such as this LINQPad program demonstrates:
void Main()
{
Injectable i1 = new Injectable();
Injectable i2 = new Injectable(new Injected("A"));
Injectable i3 = new Injectable(new Injected("A"), new Injected("B"));
Debug.WriteLine("dispose a and b");
i1.Dispose();
Debug.WriteLine("dispose b");
i2.Dispose();
Debug.WriteLine("no dispose");
i3.Dispose();
}
public class Injected : IDisposable
{
public Injected(string name) { Name = name; }
public string Name { get; set; }
public void Dispose() { Debug.WriteLine(Name + " disposed"); }
}
public class Injectable : IDisposable
{
private Ownable<Injected> _A;
private Ownable<Injected> _B;
public Injectable(Injected a, Injected b)
{
_A = Ownable.NotOwned(a);
_B = Ownable.NotOwned(b);
}
public Injectable(Injected a)
{
_A = Ownable.NotOwned(a);
_B = Ownable.Owned(new Injected("B"));
}
public Injectable()
{
_A = Ownable.Owned(new Injected("A"));
_B = Ownable.Owned(new Injected("B"));
}
public void Dispose()
{
_A.Dispose();
_B.Dispose();
}
}
public class Ownable<T> : IDisposable
where T : class
{
private readonly T _Instance;
private readonly Action _CleanupAction;
public Ownable(T instance, bool isOwned)
{
_Instance = instance;
if (isOwned)
{
IDisposable disposable = instance as IDisposable;
if (disposable == null)
throw new NotSupportedException("Unable to clean up owned object, does not implement IDisposable");
_CleanupAction = () => disposable.Dispose();
}
}
public Ownable(T instance, Action cleanupAction)
{
_Instance = instance;
_CleanupAction = cleanupAction;
}
public T Instance { get { return _Instance; } }
public void Dispose()
{
if (_CleanupAction != null)
_CleanupAction();
}
}
public static class Ownable
{
public static Ownable<T> Owned<T>(T instance)
where T : class
{
return new Ownable<T>(instance, true);
}
public static Ownable<T> Owned<T>(T instance, Action cleanupAction)
where T : class
{
return new Ownable<T>(instance, cleanupAction);
}
public static Ownable<T> NotOwned<T>(T instance)
where T : class
{
return new Ownable<T>(instance, false);
}
}
A different note can be made here either.
It depends on what is your MyClass is doing actually.
For example, if we are talking about a class that reads video stream from device, after applies some filters to it and writes data to a user specified file, where file writing is made by stream passed from the outside, say like this:
public class VideoProcessor : IDisposable {
private FileStream _videoFile = null;
private VideoProcessor() {}
//user specified FileStream
public VideoProcessor(FileStream fs) {_videoFile = fs;}
public void Dispose() {
_videoFile.Dispose(); //Dispose user passed FileStream
}
}
disposing passed stream object during dispose call, makes actually sence.
In other cases, yes, it's better to not destroy object, if you are not an owner of it. Leave it to the caller to decide when it is appropriate time to do that.
I am supposed to create a context object for the current instance of the user, and the code is
public class WorkoutContext {
protected static WorkoutContext mWorkoutContext ;
protected WorkOut mWorkOut;
protected WorkoutContext(WorkOut workout)
{
mWorkOut= workout;
}
public static WorkoutContext CreateContext(WorkOut workout))
{
if (mWorkoutContext == null)
{
mWorkoutContext = new WorkoutContext (form);
}
else
{
if (workout != mWorkoutContext.WorkOut)
{
mWorkoutContext = new WorkoutContext (workout);
}
}
return mWorkoutContext ;
}
}
In concurrent environment, for each user it is creating an instance for WorkOutContext but not release the instance after the request process completion. To Overcome this issue modified the CreateContext method as follow
public class WorkoutContext {
protected WorkoutContext mWorkoutContext ;
protected WorkOut mWorkOut;
protected WorkoutContext(WorkOut workout)
{
mWorkOut= workout;
}
public static WorkoutContext CreateContext(WorkOut workout))
{
return new WorkoutContext(workout);
}
}
Is there any other way to implement to have only one instance of WorkoutContext for the same WorkOut instance.
Try something like this:
public class WorkoutContext {
protected WorkOut mWorkOut;
private static Dictionary<WorkOut, WorkoutContext> dic = new ...;
private static object lockObj = new object();
protected WorkoutContext(WorkOut workout)
{
mWorkOut= workout;
}
public static WorkoutContext CreateContext(WorkOut workout)
{
lock(lockObj) {
if (dic.ContainsKey(workout))
return dic[workout];
var wc = new WorkoutContext(workout)
dic.Add(workout, wc);
return wc;
}
}
}
i try to write a kind of repository for effective Add,Update, Delete etc. But i am so confused how can i dispose my 2 class ( ErpEntities and DataRepository) there are more advise but also more conflicts on google. i want to make disposing after return value. Shorthly and effectivelly :(
Best regards...
namespace WinApp.EF
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnSave_Click(object sender, EventArgs e)
{
using (ErpEntities erp = new ErpEntities())
{
erp.SaveCustomer(textBox1.Text, textBox2.Text);
}
}
}
public class ErpEntities : IDisposable
{
public int SaveCustomer(string Name, string SurName)
{
using (DataRepository<Customer> repository = new DataRepository<Customer>(new TestErpEntities()))
{
return repository.Add(new Customer() { Name = Name, SurName = SurName });
}
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
public interface IRepository<T> : IDisposable where T : class
{
int Add(T entity);
}
public class DataRepository<T> : IRepository<T> where T : class
{
private TestErpEntities _context;
public DataRepository()
{
}
public DataRepository(TestErpEntities context)
{
_context = context;
}
public int Add(T entity)
{
_context.AddObject(typeof(T).Name, entity);
int saveValue = _context.SaveChanges();
return saveValue;
}
public void Dispose()
{
if (_context != null)
_context.Dispose();
}
}
}
I think this is what you want:
public class ErpEntities : IDisposable
{
public int SaveCustomer(string Name, string SurName)
{
using(DataRepository repository = new DataRepository<Customer>(new TestErpEntities()))
{
return repository.Add(new Customer() { Name = Name, SurName = SurName });
} // This using statment ensures that the DataRepository is Dispose()'d when the method exits
}
#region IDisposable Members
public void Dispose()
{
// You could eliminate this as there's nothing in your
// ErpEntities class that needs disposing
}
#endregion
}
public class DataRepository<T> : IRepository<T> where T : class
{
private TestErpEntities _context;
public DataRepository()
{
}
public DataRepository(TestErpEntities context)
{
_context = context;
}
public int Add(T entity)
{
_context.AddObject(typeof(T).Name, entity);
int saveValue = _context.SaveChanges();
return saveValue;
}
public void Dispose()
{
if (_context != null)
_context.Dispose();
}
}
The class destructor (~DataRepository()) and the GC.SupressFinalizer() are not necessary because you don't have any unmanaged resources to release. Many would argue that it's part of the IDisposable pattern, but IMO it's unnecessary.
Also, this:
new DataRepository<Customer>().Dispose();
is completely redundant and unnecessary. What you're doing here is creating this object only to destroy it. It has no other function and is just waste of memory/cpu cycles.
From what you posted, ErpEntities doesn't need to implement IDisposable. It doesn't 'own' anything.
If it did, new ErpEntities().SaveCustomer(...) would be the wrong way to use it.
The DataRepository class doesn't need the destructor (~DataRepository()) and the call(s) to GC.SuppressFinalize(this) can all be removed too.
What you should be left with:
if a class contains (owns) an IDisposable class it should implement IDisposable as well and forward the calls to Dispose()
the calling code should use IDisposable classes in a using(...) { } block.
don't mess with destructors unless you have an unmamaged resource (and even then there are better options)