Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
464 views
in Technique[技术] by (71.8m points)

c# - How can I tell the Web API / Castle Windsor routing engine to use a different database instance in my Repository?

My understanding of the flow of events with an ASP.NET Web API Castle Windsorized app that uses Models, Repositories, and Controllers:

0) The client calls a REST method via a URI such as:

http://localhost:28642/api/platypi/Count

1) Castle Windsor's routing engine maps intercepts that incoming call, sending the registered concrete class that implements the interface platypiController has as an arg in its constructor.

2) That constructor determines which of its methods is to be called (what corresponds to "Count" in this case).

3) That Controller method calls a corresponding method on the Repository.

4) The code is run, the data gathered and returned, and the user thinks it's all so easy (one extreme viewpoint) or magical (another, slightly less extreme, viewpoint).

I've created a pair of projects that utilize this and it so far works just dandy. We have several instances of databases for different users (DB1 for a particular set of customers, DB2 for another, etc.) The tables are almost but not quite identical (not guaranteed to remain such), and the queries against those tables are similar.

My conundrum/challenge is how or where to intercept the routing to go this way or that based on which "class" of user is calling.

I'm thinking that I need N Repositories implementing each interface, such as:

interface FooBar

class PhooBar : FooBar // targets DB#1
class PhooeyBar : FooBar // targets DB#2
class PoohBear : FooBar // targets DB#3

But then, how do I tell Castle Windsor or Web API which concrete class/Repository I want?

At any given time, there will be requests coming into the Web API / Castle Windsor app from clients who need to be served DB#1 data, other clients who need DB#2 data, and yet users who need DB#3 data.

Is this something that's accomplished in the URI, such as:

http://localhost:28642/api/platypi/Count/1 

(where the appended number indicates which DB to use)

?

or:

http://localhost:28642/api/platypi/Count/PhooBar

or...???

In many cases, the ONLY thing that will have to change between one Repository class and another is the connection string in the constructor. Specifically, this:

@"Provider=Microsoft.ACE.OLEDB.12.0;User ID=qypav1;Password=QqPamPoamMSET;Data Source=C:CatcherNTheRyeDATAOMDDAT03.MDB;Jet OLEDB:System database=C:Catch22Datarip.mdw"))

...will need to be:

@"Provider=Microsoft.ACE.OLEDB.12.0;User ID=qypav1;Password=QqPamPoamMSET;Data Source=C:CatcherNTheRyeDATAOMDDAT01.MDB;Jet OLEDB:System database=C:Catch22Datarip.mdw"))

(OMDDAT03 becomes OMDDAT01)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

you can use dependency injection to place your dbContext into UnitOfWork :

public interface IRepository<T> where T : class
{
    IQueryable<T> GetAll();

    void Add(T entity);

    void Delete(T entity);

    void DeleteAll(IEnumerable<T> entity);

    void Update(T entity);

    bool Any();
}

public class Repository<T> : IRepository<T> where T : class
{
    private readonly IDbContext _context;
    private readonly IDbSet<T> _dbset;

    public Repository(IDbContext context)
    {
        _context = context;
        _dbset = context.Set<T>();
    }

    public virtual IQueryable<T> GetAll()
    {
        return _dbset;
    }

    public virtual void Add(T entity)
    {
        _dbset.Add(entity);
    }

    public virtual void Delete(T entity)
    {
        var entry = _context.Entry(entity);
        entry.State = EntityState.Deleted;
        _dbset.Remove(entity);
    }

    public virtual void DeleteAll(IEnumerable<T> entity)
    {
        foreach (var ent in entity)
        {
            var entry = _context.Entry(ent);
            entry.State = EntityState.Deleted;
            _dbset.Remove(ent);
        }
    }

    public virtual void Update(T entity)
    {
        var entry = _context.Entry(entity);
        _dbset.Attach(entity);
        entry.State = EntityState.Modified;
    }

    public virtual bool Any()
    {
        return _dbset.Any();
    }
}

and finally:

public interface IUnitOfWork : IDisposable
{
    IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;

    void Save();
}

public class UnitOfWork<TContext> : IUnitOfWork where TContext : IDbContext, new()
{
    private readonly IDbContext _ctx;
    private readonly Dictionary<Type, object> _repositories;
    private bool _disposed;

    public UnitOfWork()
    {
        _ctx = new TContext();
        _repositories = new Dictionary<Type, object>();
        _disposed = false;
    }

    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
    {
        if (_repositories.Keys.Contains(typeof(TEntity)))
        {
            return _repositories[typeof(TEntity)] as IRepository<TEntity>;
        }
        var repository = new Repository<TEntity>(_ctx);

        _repositories.Add(typeof(TEntity), repository);

        return repository;
    }

    public void Save()
    {
        _ctx.SaveChanges();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (this._disposed) return;

        if (disposing)
        {
            _ctx.Dispose();
        }

        this._disposed = true;
    }
} 

I just copy and past the code from one of my projects, by using the same way you can have several dbcontext in your application.

also take a look at this solution: Multiple DbContexts in N-Tier Application


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...