C#: Helper Method Dependency Injection within Constructor - c#

I have a IData interface that handles the SQL data access logic and as well as retrieving data from SQL Server:
public interface IData
{
Task<IEnumerable<string>> GetUsers();
}
I have a Emailer class that sends an email with the list of Users and currently I am injecting IData via the constructor and accessing the GetUsers() method within another Method of the Emailer class:
public class Emailer
{
private readonly IData _data;
public Emailer(IData data)
{
_data = data;
}
public async Task Send()
{
var users = await _data.GetUser(); // access data here
}
}
In an act to try and refactor this code and apply the Single Responsibility principle, I want to abstract away the GetUser() logic into its own seperate class however how can I do this without having to initialise IData in the constructor of the new class to avoid having to pass the IData object as a parameter when newing up the class?
Example:
public class UserData
{
private readonly IData _data;
public UserData(IData data)
{
_data = data; // not ideal as I'd have to pass the object from the Emailer class and other classes that call Emailer
}
public async Task Fetch()
{
var users = await _data.GetUser(); // access data here
}
public async Task ManipulateUser(){} // example of future extensibility hence the reason for a seperate class
}
Could implementing a factory pattern to solve this problem (if yes, how?) or any other ideas?
TIA

Compare interfaces to black boxes. They do stuff, but you have no idea of how they do it.
But, if you look at the interface name and have no idea of what they are doing, you got it wrong.
In this case, IData seems like a database god object. Am I correct? Does it handle all your SQL operations? If so, divide it into different interfaces which all have a clear responsibility. "I handle DB access for user objects" = IUserData.
Regarding methods, C# is an object-oriented language, and classes (and interfaces) are the primary way of letting objects communicate. You won't get any benefits in this case if you try to inject methods instead.
Update
Do not refractor code to remove dependencies. composition makes the code more robust. Instead, use a Inversion Of Control container to create your classes.
Read this article to get started: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-6.0

Can't you just abstact bind UserData to an interface, called IUserData and inject that into your Emailer class if needed?
I'm on my mobile right now but if you like I can post a code example later if you don't understand.
--UPDATE--
Here is the updated code.
//Refactor your existing classes to look like this.
public interface IData
{
Task<IEnumerable<string>> GetUsers();
}
public interface IEmailer
{
Task Send();
}
public class Emailer : IEmailer
{
private readonly IUserData _userData;
public Emailer(IUserData userData)
{
_userData = userData;
}
public async Task Send()
{
var users = await _userData.Fetch(); // access data here
}
}
public interface IUserData
{
Task Fetch();
Task ManipulateUser();
}
public class UserData : IUserData
{
private readonly IData _data;
public UserData(IData data)
{
_data = data;
}
public async Task Fetch()
{
var users = await _data.GetUser();
}
public async Task ManipulateUser() { }
}
//Example of class calling Emailer
public interface IRandomClass
{
Task RunSomeCode();
}
public class RandomClass : IRandomClass
{
private readonly IEmailer _emailer;
public RandomClass(IEmailer emailer)
{
_emailer = emailer;
}
public async Task RunSomeCode()
{
//Example code
await _emailer.Send();
}
}
Binding the dependencies (assuming you're using .netcore)
services.AddScoped<IUserData, UserData>();
services.AddScoped<IEmailer, Emailer>();
services.AddScoped<IRandomClass, RandomClass>();
This should give you a good baseline to work from.
Let me know if you need anything else.
Happy coding!

You seem to redesign a class prematurely violating the YAGNI principle. If you aren't extending UserData right now, there is no need to introduce a further abstraction that does nothing more than the code already did.
When you do have extra responsibilities then you will create the UserData object passing IData into its constructor. Then you pass the UserData instance into the Emailer constructor. You basically switch one object for another.

IData seems too generic for this use case. You can instead introduce IUserData
which would be only responsible for handling data access for the User.
Then your setup will look like this:
public interface IUserData
{
Task<IEnumerable<string>> GetUsers();
}
public class UserData: IUserData
{
public async Task<IEnumerable<string>> GetUsers()
{ ... }
}
public interface IEmailer
{
Task Send();
}
public class Emailer : IEmailer
{
private readonly IUserData _userData;
public Emailer(IUserData userData)
{
_userData = userData;
}
public async Task Send()
{
var users = await _userdata.GetUser();
}
}
Alternatively, you can have 3 layers with a generic Data class in charge of all the data access operations and have the UserData class fine-grain it. This of course depends on how large and unmanageable can this data service become. I personally prefer to have tailor-made services for each data access use case.

Related

Writing a client wrapper class to isolate internal details of the client whose class implements IDisposable but interface does not

I am writing a client wrapper around an external client that is defined in a NuGet package. The NuGet package contains below interface and the class.
public interface IServiceClient
{
Task<Job> CreateJobAsync(JobDetails jobdetails);
}
public class ServiceClient : IServiceClient, IDisposable
{
public async Task<Job> CreateJobAsync(JobDetails jobDetails)
{
// Some processing and returns a job that contains required response and status
return job;
}
}
In my application, I write a client wrapper around the service client as below:
public interface IServiceClientWrapper
{
Task<ResponseDto> PostAsync(RequestDto request);
}
public class ServiceClientWrapper : IServiceClientWrapper
{
private static IServiceClient serviceClient;
public static void Init()
{
// See below for defintion
serviceClient = ClientFactory.Create();
}
public async Task<ResponseDto> PostAsync(RequestDto request)
{
// Convert request to JobDetails as required
var job = await serviceClient.CreateJobAsync(jobDetails);
// Convert job to ResponseDto and return
return response;
}
// Since ServiceClient implements IDisposable
public static void Close()
{
if (serviceClient != null)
{
((ServiceClient)serviceClient).Dispose();
}
}
}
internal static class ClientFactory
{
public static IServiceClient ServiceClient { get; set; }
public static IServiceClient Create()
{
if (ServiceClient != null)
{
// Used during unit testing
return ServiceClient;
}
return new ServiceClient(APIBaseAddress, AccessKey);
}
}
Questions:
Since the interface isn't marked IDisposable, I introduce Init and Close methods to do that. Is there a better way to handle this?
Having the serviceClient as static, is it thread-safe since I always invoke the non-static CreateJobAsync method with new paramters for each request?
I'd suggest that IDisposable is a detail of the concrete implementation of IServiceClientWrapper i.e. ServiceClientWrapper
It is not necessarily apart of the IServiceClientWrapper, as you may in theory have implementations which don't need to dispose of anything.
So as the comments suggest, ServiceClientWrapper should implement IDisposable.

DI and Lifetime Management

what is the 'best' way to manage the lifecycle of a disposable object when it is injected into another class. The example I keep running into is when running database queries using entity framework in a class that has a long lifetime.
Here is an example
public class CustomerViewModel
{
private ICustomerRepository _customerRepository;
public CustomerViewModel(ICustomerRepository customerRepository)
{
_customerRepository = customerRepository;
}
public void AddCustomer(Customer customer)
{
_customerRepository.Customers.Add(customer);
_customerRepository.SaveChanges();
}
}
The code above looks perfectly innocent to me, however the _customerRepository object exists for as long as the CutomerViewModel exists for, which is much longer than it should.
If I were writting this code without DI i would do this:
public class CustomerViewModel
{
public void AddCustomer(Customer customer)
{
using (var customerRepository = new CustomerRepository())
{
customerRepository.Customers.Add(customer);
customerRepository.SaveChanges();
}
}
}
Which handles the lifecycle of CustomerRepository correctly.
How is this supposed to be managed when a class requires a Disposable object to have a shorter lifetime than itself?
The method I am using now is to create a RepositoryCreator object, which knows how to initialize a repository, but this feels wrong:
public class CustomerViewModel
{
private ICustomerRepositoryCreator _customerRepositoryCreator;
public CustomerViewModel(ICustomerRepositoryCreator customerRepositoryCreator)
{
_customerRepositoryCreator= customerRepositoryCreator;
}
public void AddCustomer(Customer customer)
{
using (var customerRepository = _customerRepositoryCreator.Create())
{
customerRepository.Customers.Add(customer);
customerRepository.SaveChanges();
}
}
}
UPDATE
So would doing something like this be preferable, it could be made generic but for the sake of this example I will not do this.
public class CustomerViewModel
{
private ICustomerRepository _customerRepository;
public CustomerViewModel(ICustomerRepository customerRepository)
{
_customerRepository = customerRepository;
}
public void AddCustomer(Customer customer)
{
_customerRepository.Add(customer);
}
}
public class CustomerRepository : ICustomerRepository
{
private readonly DbContext _dbContext;
public CustomerRepository(DbContext dbContext)
{
_dbContext = dbContext;
}
public void Add(Customer customer)
{
_dbContext.Customers.Add(customer);
_dbContext.Customers.SaveChanges();
}
}
And have a proxy which manages lifetime
public class CustomerRepositoryLifetimeProxy : ICustomerRepository
{
private readonly _container;
public CustomerRepositoryLifetimeProxy(Container container)
{
_container = container;
}
public void Add(Customer customer)
{
using (Container.BeginScope()) //extension method
{
    ICustomerRepository cRepo = Container.Resolve<ICustomerRepository>();
cRepo.Add(customer);
} // releases the instance
}
}
If this is better, should the Proxy know about the DI container, or should it rely on a factory?
The problem here is that your AddCustomer method in your ViewModel does to much. The viewmodel should not be responsible of handling business logic, and the repositories consumer shouldn't know nothing about committing a unit of work and should not be able to add a customer to the list of customers.
So instead, refactor your ICustomerResository to the following:
public interface ICustomerRepository
{
void Add(Customer customer);
}
In this case, the Add method should be atomic and do the commit itself. This way the viewmodel can depend on that interface and in case the viewmodel outlives the customer repository, you can wrap the real repository with a proxy:
public class CustomerRepositoryProxy : ICustomerRepository
{
private readonly Func<ICustomerRepository> repositoryFactory;
public CustomerRepositoryProxy(Func<ICustomerRepository> repositoryFactory) {
this.repositoryFactory = repositoryFactory;
}
public void Add(Customer customer) {
var repository = this.repositoryFactory.Invoke();
repository.Add(customer);
}
}
Of course this will start to become quite cumbersome if you have dozens of those IXXXRepository interfaces. In that case, you might want to migrate to one generic interface instead:
public interface IRepository<TEntity>
{
void Add(TEntity entity);
}
This way you can have one single proxy for all repositories:
public class RepositoryProxy<TEntity> : IRepository<TEntity>
{
private readonly Func<IRepository<TEntity>> repositoryFactory;
public CustomerRepositoryProxy(Func<IRepository<TEntity>> repositoryFactory) {
this.repositoryFactory = repositoryFactory;
}
public void Add(TEntity entity) {
var repository = this.repositoryFactory.Invoke();
repository.Add(entity);
}
}
In that case (assuming you wire your object graphs by hand) you can build up the viewmodel as follows:
new CustomerViewModel(
new RepositoryProxy<Customer>(
() => new CustomerRepository(unitOfWork)));
You can even take it one step further and implement the command/handler pattern and query/handler pattern. In that case you don't inject a IRepository<Customer> into your view model, but you inject an ICommandHandler<AddCustomer> into the view model and instead of injecting the AddCustomerCommandHandler implementation into the view model, you inject a proxy that creates the real handler when needed:
public class LifetimeScopedCommandHandlerProxy<TCommand> : ICommandHandler<TCommand>
{
private readonly Func<ICommandHandler<TCommand>> decorateeFactory;
public LifetimeScopedCommandHandlerProxy(
Func<ICommandHandler<TCommand>> decorateeFactory) {
this.decorateeFactory = decorateeFactory;
}
public void Handle(TCommand command) {
var decoratee = this.decorateeFactory.Invoke();
decoratee.Handle(command);
}
}
The view model will look as follows:
public class CustomerViewModel
{
private ICommandHandler<AddCustomer> addCustomerCommandHandler;
public CustomerViewModel(ICommandHandler<AddCustomer> addCustomerCommandHandler) {
this.addCustomerCommandHandler = addCustomerCommandHandler;
}
public void AddCustomer(Customer customer)
{
this.addCustomerCommandHandler.Handle(new AddCustomer(customer));
}
}
And the object graph will look similar as before:
new CustomerViewModel(
new LifetimeScopedCommandHandlerProxy<AddCustomer>(
() => new AddCustomerCommandHandler(unitOfWork)));
Of course, it will be much easier building these object graphs when using a container.
UPDATE
If you use a DI container, and you're not running in something like a web request, you will have to start a new 'scope' or 'request' explictly to inform the container what to do. With Simple Injector your proxy will looks like this:
public class LifetimeScopedCommandHandlerProxy<TCommand> : ICommandHandler<TCommand>
{
private readonly Container container;
private readonly Func<ICommandHandler<TCommand>> decorateeFactory;
// Here we inject the container as well.
public LifetimeScopedCommandHandlerProxy(Container container,
Func<ICommandHandler<TCommand>> decorateeFactory)
{
this.container = container;
this.decorateeFactory = decorateeFactory;
}
public void Handle(TCommand command) {
// Here we begin a new 'lifetime scope' before calling invoke.
using (container.BeginLifetimeScope())
{
var decoratee = this.decorateeFactory.Invoke();
decoratee.Handle(command);
}
// When the lifetime scope is disposed (which is what the using
// statement does) the container will make sure that any scope
// instances are disposed.
}
}
In that case your configuration might look like this:
// This instance lives as long as its scope and will be disposed by the container.
container.RegisterLifetimeScope<IUnitOfWork, DisposableUnitOfWork>();
// Register the command handler
container.Register<ICommandHandler<AddCustomer>, AddCustomerCommandHandler>();
// register the proxy that adds the scoping behavior
container.RegisterSingleDecorator(
typeof(ICommandHandler<>),
typeof(LifetimeScopedCommandHandlerProxy<>));
container.Register<CustomerViewModel>();
In general it is up to the creator to dispose a disposable object as soon es it is done with its usage. If your injected object can live through entire application lifecycle, i.e. without needing to dispose it in the meantime, than the normal DI approach (your first code block) is a good way to go. However, if you need to dispose the object as soon as possible, than a factory approach makes much more sense (last code block).

C# Interfaces implementation

I don't know how manage properly the interfaces in C#. My goal is to have an abstract class for my Business Layer Services that have some common methods (like Save(), Dispose()), that call different DAL repository methods. I wish to avoid to repeat in all my services something like:
public Save()
{
repository.Save();
}
I have a scenario similar to that:
Interface
namespace Common
{
public interface IRepository
{
void Save;
void Dispose;
}
}
DAL
namespace DAL
{
public Repository : IRepository
{
public void Save() {};
public void Dispose() {};
public void Add() {}
}
}
BL
namespace BL
{
public abstrac BaseService
{
protected IRepository repository;
protected BaseService(IRepository repo)
{
repository = repo;
}
public Save()
{
repository.Save();
}
}
//...
//Tentative 1
public Service : BaseService
{
private Repository rep;
public Service()
: base(new DAL.Repository())
{
rep = base.repository; // ERROR: cannot convert IRepository to Repository
}
}
}
I tried also this:
//Tentative 2
public Service : BaseService
{
private IRepository rep;
public Service()
: base(new DAL.Repository())
{
rep = base.repository; // OK
}
public void Add()
{
rep.Add() // ERROR: IRepository doesn't contain a definition for 'Add'
}
}
I know I could define in the interface all the methods I want to use, but I'll will have to manage a lot of problems with generic types and, as you should have understand from my question, I'm quite new in C# and I wish to avoid complexity is is possible, utill I'll be more expert at least :)
Firstly I think you're having a name clash with you member
IRepository rep.
Try using
DAL.IRepository rep
The reason that you're getting an error is that you've defined "Add" as something unique to "Repository". Your member variable is an "IRepository" allowing you to put anything that implements "IRepository" onto it.
Just because you CAN put a Repository into it, doesn't mean that everything on it is going to be a repository. (Think of it look good 'ol fingers and thumbs, all thumbs are fingers, but not all fingers are thumbs)
If you NEED to call add on any repository, then add it to the interface. Else, you need to decide whether or not that member should be IRepository or Repository.
Alternatively, you COULD use
Repository myRep = rep as Repository;
if(rep!=null)
{
myRep.Add();
...
profit();
}
public Service()
: base(new DAL.Repository())
{
rep = (Repository)base.repository;
}
This way u will get the Add() service which is not a part of IRepository but a newer implementation in the extended class.
Seeing as your main problem is the lack of accessibility to the Add method, and seeing as this is a relative common method anyway, I would firstly recommend adding it to your IRepository, so it looks like this:
public interface IRepository
{
void Add();
void Save();
void Dispose();
}
You would then implement your appropriate repositories whilst inheriting from IRepository. Now, understandably you may want to be able to access custom methods on a Repository. In order to resolve this what you could do is have your BaseService accept a generic repository:
public BaseService<T> where T : IRepository
{
protected T repository { get; set; }
protected BaseService(T repo)
{
repository = repo;
}
}
Then a service would look like this
public UserService : BaseService<UserRepository>
{
public UserService() : base(new DAL.UserRepository())
{
// base.Repository is now a UserRepository.
}
}
With this implementation your UserService will be able to access all of the methods that UserRepository exposes, as it's strongly typed with the generic. Hope this helps.

Is my context too coupled with my repository?

Learning Entity Framework, Repositories and IOC, what I am trying to achieve is to implement the repository pattern in order to change my data source provider.
Please see this example from an open-source project:
namespace MyApp.Domain.Interfaces
{
public interface IEFContext : IDisposable
{
}
}
EFContext (implementing IEFContext)
namespace MyApp.Data.Context
{
public class EFContext : DbContext, IEFContext
{
public const string DBConnectionName = #"MyDBName";
public EFContext() : base(DBConnectionName)
{
}
public DbSet<Member> Member { get; set; }
}
}
IMemberRepository
namespace MyApp.Domain.Interfaces.Repositories
{
public interface IMemberRepository
{
Member GetUser(string username);
}
}
MemberRepository (implementing IMemberRepository)
namespace MyApp.Data.Repositories
{
public class MemberRepository : IMemberRepository
{
private readonly EFContext _context;
public MemberRepository(IEFContext context)
{
_context = context as EFContext;
}
// update
public Member GetUser(string username)
{
return _context.Member.SingleOrDefault(name => name.UserName.ToUpper().Contains(username.ToUpper()));
}
}
}
and this is my application console using Unity
Console App
namespace MyApp.ConsoleApp
{
public class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<IEFContext, EFContext>();
container.RegisterType<IMemberRepository, MemberRepository>();
var repository = container.Resolve<MemberRepository>();
var user = repository.GetUser("johnDoe");
Console.WriteLine(user.Email);
Console.ReadLine();
}
}
}
My question is the following:
if I decide to add a new context, such as:
namespace MyApp.Data.Context
{
public class EFContext2 : DbContext, IEFContext
{
public const string DBConnectionName = #"MyNewDBName";
public EFContext2() : base(DBConnectionName)
{
}
public DbSet<Member> Member { get; set; }
}
}
I should have only to change the dependency like:
namespace MyApp.ConsoleApp
{
public class Program
{
static void Main(string[] args)
{
...
container.RegisterType<IEFContext, EFContext2>();
...
}
}
}
but in this example my MemberRepository is loosely-coupled with my first context. So if I have to change my Context I must also change my repository.
I would be please to have your point of view on this.
Kind regards
but in this example my MemberRepository is loosely-coupled with my first context. So if I have to change my Context I must also change my repository.
Yes it is, but it's a one line change from:
private readonly EFContext _context;
to
private readonly IEFContext _context;
And not casting on your constructor:
public MemberRepository(IEFContext context)
{
_context = context;
}
Now, you can inject any kind of concrete context that implements IEFContext.
Just think about this: What you're trying to do with dependency injection is, well, inject dependencies. But, how do you do that? Well, you do that by generalizating those dependencies. I mean, you want to be able to use different context, then you use an interface IEFContext instead of a concrete context. That's why your constructor expects an interface.
But, that's the first part, know, the problem with your code is that when you say
_context = context as EFContext;
You're downcasting the interface and saying: This interface is an EFContext. You're loosing the generality. Know when you try to inject a, say, SQLContext, you'll not be able since although it's and IEFContext it isn't an EFContext. That's why you remove the as EFContext part and just let
_context = context;
Now as for the second part, being general and expecting and receiving an interface is just the first part. You now need to tell the compiler that you're expecting a generic context IEFContext, but you need also tell him that no matter which context you receive you should be able to, say, GetUsers. That's where your interface comes into play. You know declare the property public Member GetUser{} within your interface forcing and guaranteeing then that no matter which context arrive you'll be able to get your users.
I hope this to be a little simple to understand. Good luck.

Availability of Methods on the basis of Constructor

I have a Class called Repository for accessing (Read/Write to and from) Database.
The projects that require access to the database create an object of Repository and pass the connection string as a constructor parameter for the repository to work for that particular project.
I have few methods in the Repository that i want to be available only if certain connection strings are passed. I don't want them to be available if some different connection string is passed.
Is there any way I can accomplish that?
I have never used method header technique, can that help? if yes, how can i use it? if no, please let me know if there is any other way to achieve my goal.
Regards.
You could use a factory method pattern to accomplish your goal.
Create a RepositoryFactory class that takes in the connection string and returns a different repository based upon the contents of the string.
public class RepositoryFactory {
public IRepository GetRepository(string connection)
{
if(SomeTestOnConnect(connection))
return new SimpleRepository(connection);
else
return new FullRepository(connection);
}
}
With this when someone wants a repository they call the GetRepository method.
Sort of doing:
if (_connection == "XYZ")
throw new InvalidOperationException();
Is it possible that you could refactor your approach to create a new class:
public class ConnectionInfo
{
public string ConnectionString { get; set; }
public bool IsLimitedAccess { get; set; }
}
Then, in each repository method not allowed, if limited access, return null or throw exception or something?
If you know in advance whether you'll need the extra methods, you could have a base version which doesn't support the extra methods, and a derived type which does. The constructor for the derived type could throw an exception if required information is not provided.
Using a factory method instead of a constructor would allow a base or fancy object to be constructed based upon the passed-in connection string; if you just have one factory method, though, you'll have to typecast the result if you want to use the extra methods.
The best approach may be to have a factory method for each defined type, with a guarantee that it will either return an object that's at least as good as the requested type or throw an exception if it can't. This approach would allow for future expansion in case more further-derived types become available.
If you want to limit the available methods, you could use a pattern like this.
Use the factory to get an instance like this:
var repo = RepositoryFactory.Resovle<IFullRepository>("connection string");
And the code that makes this work is here
public class RepositoryFactory
{
public static T Resovle<T>(string connection) where T: IRepository
{
IRepository instance = new Repository(connection);
return (T)instance;
}
private class Repository : IFullRepository
{
private string _connection;
public Repository(string connection)
{
_connection = connection;
}
public object Get(int id)
{
// select
}
public void Save(object o)
{
// upate
}
public void Create(object o)
{
// create
}
public void CustomMethodOne()
{
// do something specialized
}
public void CustomMethodTwo()
{
// do something specialized
}
}
}
public interface IRepository
{
object Get(int id);
void Save(object o);
void Create(object o);
}
public interface IRepositoryProjectOne: IRepository
{
void CustomMethodOne();
}
public interface IRepositoryProjectTwo: IRepository
{
void CustomMethodTwo();
}
public interface IFullRepository: IRepositoryProjectOne, IRepositoryProjectTwo
{
}
The downsides are, you get an explosion of Interfaces to control what methods are exposed. However, it is possible to cast between the various interfaces, but it avoids having to throw exceptions when a method isn't implemented.
There doesn't seem to be a perfect way to do this however I think your calling method needs to know whether or not it is allowed to write to the Repository as another poster has stated the availability of methods is something that needs to be known at compile time rather than run time.
The solution would be to create two interfaces, one that offers full functionality and one that offers limited functionality.
public interface IRepository : IRead
{
void Write(object o);
}
public interface IRead
{
object Read();
}
Your Repository object then implements the top interface.
public class Repository : IRepository
{
private readonly string _connectionString;
public Repository(string connectionString)
{
_connectionString = connectionString;
}
public object Read()
{
// Do stuff
}
public void Write(object o)
{
// Do stuff
}
}
You can then have a class that determines if the connection string demands a read only repository or not and exposes 2 different methods to return the given type of interface (meaning you need to know the type at compile time).
public static class RepositoryFactory
{
public static bool ConnectionStringIsReadOnly(string connectionString)
{
return connectionString.Contains("user=hacker");
}
public static IRead GetReadOnlyRepository(string connectionString)
{
return new Repository(connectionString);
}
public static IRepository GetRepository(string connectionString)
{
if (ConnectionStringIsReadOnly(connectionString)) throw new ArgumentException(#"Given connectionString is not allowed full repository access", "connectionString");
return new Repository(connectionString);
}
}
You can then consume this as follows, seperating the points where you try to do actions that require full access by checking that you have a version of IRepository or of IRead only.
public class Program
{
public void ConsumeRepository(string connectionString)
{
IRead reader = null;
IRepository repository = null;
if (RepositoryFactory.ConnectionStringIsReadOnly(connectionString))
reader = RepositoryFactory.GetReadOnlyRepository(connectionString);
else
{
repository = RepositoryFactory.GetRepository(connectionString);
reader = repository;
}
object o = reader.Read();
// do something with o
// if allowed then write o to repository
if (repository != null)
{
repository.Write(o);
}
}
}

Categories