I know there are a few similar question out there regarding this issue with structure map, but my issue seems to not be resolvable with the solutions they needed. I must state I have used this same setup many times, but cannot see why this code is causing issues.
Here are all of the classes I think that are needed for help with troubleshooting my code.
ControllerConvention.cs
public class ControllerConvention : IRegistrationConvention
{
public void ScanTypes(TypeSet types, Registry registry)
{
foreach (Type type in types.AllTypes())
{
if (type.CanBeCastTo(typeof(Controller)) && !type.IsAbstract)
{
registry.For(type).LifecycleIs(new UniquePerRequestLifecycle());
}
}
}
}
IoC.cs
public static class IoC
{
public static IContainer Container { get; set; }
static IoC()
{
Container = new Container();
}
}
StandardRegistry.cs
public class StandardRegistry : Registry
{
public StandardRegistry()
{
Scan(scan =>
{
scan.TheCallingAssembly();
scan.Assembly("PotSmart.Service");
scan.Assembly("PotSmart.Data");
scan.WithDefaultConventions();
});
}
}
StructureMapDependencyResolver.cs
public class StructureMapDependencyResolver : IDependencyResolver
{
private readonly Func<IContainer> _factory;
public StructureMapDependencyResolver(Func<IContainer> factory)
{
_factory = factory;
}
public object GetService(Type serviceType)
{
if (serviceType == null)
{
return null;
}
var factory = _factory();
return serviceType.IsAbstract || serviceType.IsInterface
? factory.TryGetInstance(serviceType)
: factory.GetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _factory().GetAllInstances(serviceType).Cast<object>();
}
}
Global.asax
public IContainer Container
{
get
{
return (IContainer)HttpContext.Current.Items["_Container"];
}
set
{
HttpContext.Current.Items["_Container"] = value;
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
DependencyResolver.SetResolver(new StructureMapDependencyResolver(() => Container ?? IoC.Container));
IoC.Container.Configure(cfg =>
{
cfg.AddRegistry(new StandardRegistry());
cfg.AddRegistry(new ControllerRegistry());
});
}
Here are parts of my data and entities classes:
RepositoryBase.cs
public class RepositoryBase
{
private readonly PotSmartEntityModel1 _dataContext;
protected IDbFactory DbFactory { get; private set; }
protected PotSmartEntityModel1 DbContext
{
get
{
return _dataContext ?? DbFactory.Init();
}
}
protected RepositoryBase(IDbFactory dbFactory)
{
DbFactory = dbFactory;
var adapter = (IObjectContextAdapter)this;
var objectContext = adapter.ObjectContext;
// objectContext.CommandTimeout = 120; // value in seconds
}
}
public abstract class RepositoryBase<T> where T : class
{
private readonly PotSmartEntityModel1 _dataContext;
private readonly IDbSet<T> _dbSet;
protected IDbFactory DbFactory { get; private set; }
protected PotSmartEntityModel1 DbContext
{
get
{
return _dataContext ?? DbFactory.Init();
}
}
protected RepositoryBase(IDbFactory dbFactory)
{
DbFactory = dbFactory;
_dbSet = DbContext.Set<T>();
}
public virtual void Add(T entity)
{
_dbSet.Add(entity);
}
public virtual void Update(T entity)
{
_dbSet.Attach(entity);
DbContext.Entry(entity).State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
_dbSet.Remove(entity);
}
public virtual void Delete(Expression<Func<T, bool>> where)
{
IEnumerable<T> objects = _dbSet.Where<T>(where);
foreach (T obj in objects)
{
_dbSet.Remove(obj);
}
}
public virtual T GetById(int id)
{
return _dbSet.Find(id);
}
public virtual T GetById(string id)
{
return _dbSet.Find(id);
}
public virtual IEnumerable<T> GetAll()
{
return _dbSet.ToList();
}
public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
{
return _dbSet.Where(where).ToList();
}
public T Get(Expression<Func<T, bool>> where)
{
return _dbSet.Where(where).SingleOrDefault();
}
public virtual IQueryable<T> Query()
{
return _dbSet;
}
public virtual IQueryable<T> Query(Expression<Func<T, bool>> where)
{
return _dbSet.Where(where);
}
public virtual ObjectQuery<U> CreateQuery<U>(string query, ObjectParameter[] parameters)
{
return CastAsObjectContext().CreateQuery<U>(query, parameters);
}
public virtual ObjectQuery<U> CreateQuery<U>(string query)
{
return CreateQuery<U>(query, new ObjectParameter[0] { });
}
public virtual ObjectQuery<DbDataRecord> CreateQuery(string query, ObjectParameter[] parameters)
{
return CreateQuery<DbDataRecord>(query, parameters);
}
public virtual ObjectQuery<DbDataRecord> CreateQuery(string query)
{
return CreateQuery<DbDataRecord>(query);
}
private ObjectContext CastAsObjectContext()
{
var oContext = (DbContext as IObjectContextAdapter).ObjectContext;
return oContext;
}
}
DBFactory.cs
class DbFactory : Disposable, IDbFactory
{
private PotSmartEntityModel1 _dbContext;
public PotSmartEntityModel1 Init()
{
return _dbContext ?? (_dbContext = new PotSmartEntityModel1());
}
protected override void DisposeCore()
{
if (_dbContext != null)
{
_dbContext.Dispose();
}
}
}
IDBFactory.cs
public interface IDbFactory : IDisposable
{
PotSmartEntityModel1 Init();
}
IRepository.cs
public interface IRepository
{
}
public interface IRepository<T> where T : class
{
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(Expression<Func<T, bool>> where);
T GetById(int id);
T GetById(string id);
IEnumerable<T> GetAll();
IEnumerable<T> GetMany(Expression<Func<T, bool>> where);
IQueryable<T> Query();
IQueryable<T> Query(Expression<Func<T, bool>> where);
ObjectQuery<U> CreateQuery<U>(string query, ObjectParameter[] parameters);
ObjectQuery<U> CreateQuery<U>(string query);
ObjectQuery<DbDataRecord> CreateQuery(string query, ObjectParameter[] parameters);
ObjectQuery<DbDataRecord> CreateQuery(string query);
}
Now, sorry for so much code but that way I get all the answer out there that some in the community may ask. The issue is on my controller, I use no default constructor and do the dependency injection like the following code show:
MarkerController.cs
public class MarkerController : Controller
{
private readonly IMarkerService _markerService;
public MarkerController(IMarkerService markerService)
{
_markerService = markerService;
}
// GET: Markers
public ActionResult Index()
{
return View();
}
}
When I run the code I keep getting the following error, and have tried anything I could think of.
StructureMap.StructureMapConfigurationException: 'No default Instance is registered and cannot be automatically determined for type 'PotSmart.Data.Interfaces.IDbFactory'
I know StructureMap does not always have the clearest error messages, but I feel this meant my Entity model was not being initialized at run time for some reason.It fails during "factory.GetInstance(serviceType)". Has anyone had this error, or does anyone see what I am obviously overlooking in the code sets I have above that would cause this issue? Thanks a million as always in advance.
Related
I need to manipulate some data from a database via two different ways, Entity Framework and web service.
To simplify, lets say there are only two tables called A and B.
I am stuck on the design of this. Should I simply have two classes that derive from an interface that exposes the functions I want like so:
public interface IRepository
{
bool AddA(A a);
bool RemoveA(A a);
IEnumerable<A> GetAllA();
bool AddB(B b);
bool RemoveB(B b);
IEnumerable<B> GetAllB();
}
public class EfRepository : IRepository
{
//actual code here
}
public class ServiceRepository : IRepository
{
//actual code here
}
or should I try an approach which is more generic in nature:
public interface IRepository<T>
{
bool Add(T t);
bool Remove(T t);
IEnumerable<T> GetAll();
bool Update(T t);
}
public class EfARepository: IRepository<A>
{
//actual code here
}
public class EfBRepository : IRepository<B>
{
//actual code here
}
public class ServiceARepository: IRepository<A>
{
//actual code here
}
public class ServiceBRepository : IRepository<B>
{
//actual code here
}
The second approach seems cumbersome and repetitive since I am not really following the generic repository pattern because I'm not sure if its doable or worth the effort since Entity Framework already acts like a repository. Or would something like this be more sensible:
public class ARepository<Ef> : IRepository<A>
{
//omitted
}
//or this
public class EfRepository<A> : IRepository<A>
{
//omitted
}
But then again I can't wrap my head on injecting the context (Ef or service) into the classes and a repository of EF or vice versa doesn't really make much sense.
Please enlighten me and comment on the aforementioned designs and suggest a better approach or design for this scenario. Some examples in relation to this would be great!
I use the following approach in several projects. The example is simplified a little bit.
/// <summary>
/// THE base class for all entities.
/// </summary>
/// <typeparam name="TKey">The type of the key for the entity.</typeparam>
public abstract class Entity<TKey>
{
private TKey _id;
public Entity() : this(default(TKey))
{
}
public Entity(TKey id)
{
_id = id;
}
public Entity(Entity<TKey> source) : this(default(TKey))
{
if (source != null)
{
this._id = source._id;
}
}
public TKey Id
{
get { return _id; }
set { _id = value; }
}
public bool IsTransient()
{
return Id.Equals(default(TKey));
}
}
public interface IRepository : IDisposable
{
bool Exists();
void OpenConnection(); // helper
void CreateIfNotExists(); // helper
IQueryable<T> GetAll<T, TKey>() where T : Entity<TKey>;
IQueryable<T> GetAllIncluding<T, TKey>(params Expression<Func<T, object>>[] includeProperties) where T : Entity<TKey>;
IQueryable<T> SearchFor<T, TKey>(Expression<Func<T, bool>> predicate) where T : Entity<TKey>;
T GetById<T, TKey>(TKey id) where T : Entity<TKey>;
void Add<T, TKey>(T entity) where T : Entity<TKey>;
void Update<T, TKey>(T entity) where T : Entity<TKey>;
void Delete<T, TKey>(T entity) where T : Entity<TKey>;
void Delete<T, TKey>(TKey id) where T : Entity<TKey>;
void Save();
void Delete();
}
Then you derive all your entities from the Entity<TKey> base class and implement the repository.
public class MyRepository : IRepository
{
private DbContext _context;
public EFRepository(DbContext context)
{
if (context == null)
throw new ArgumentNullException("context");
_context = context;
}
public bool Exists()
{
return _context.Database.Exists();
}
...
public IQueryable<T> GetAll<T, TKey>() where T : Entity<TKey>
{
return _context.Set<T>();
}
public IQueryable<T> GetAllIncluding<T, TKey>(params Expression<Func<T, object>>[] includeProperties) where T : Entity<TKey>
{
IQueryable<T> query = _context.Set<T>();
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query;
}
public IQueryable<T> SearchFor<T, TKey>(Expression<Func<T, bool>> predicate) where T : Entity<TKey>
{
return _context.Set<T>().Where(predicate);
}
public T GetById<T, TKey>(TKey id) where T : Entity<TKey>
{
// use the static Equals method to accept null values
return _context.Set<T>().FirstOrDefault(x => object.Equals(id, x.Id));
}
public void Add<T, TKey>(T entity) where T : Entity<TKey>
{
if (entity != null)
{
Context.Set<T>().Add(entity); // new entity
}
}
public void Update<T, TKey>(T entity) where T : Entity<TKey>
{
if (entity != null)
{
if (object.Equals(entity.Id, default(TKey)))
Context.Set<T>().Add(entity); // new entity
else
Context.Entry<T>(entity).State = EntityState.Modified;
}
}
public void Save()
{
Context.SaveChanges();
}
...
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
try
{
if (_context != null)
_context.Dispose();
}
catch (Exception ex)
{
Debug.WriteLine("MyRepository.Dispose exception:" + ex);
}
}
}
}
public class MyUser : Entity<int>
{
public MyUser()
{
Name = null;
}
public MyUser(string user)
{
Name = user;
}
public MyUser(MyUser source) : base(source)
{
if (source != null)
{
Name = Helpers.SafeCopy(source.Name);
}
}
public string Name { get; set; }
}
Here i implemented generic repository pattern for do the CRUD operation at the same time , i would like to do the search option as well, anyone can you tell me query to do generic search options, my code is below
public interface IRepository<T> where T : class
{
IEnumerable<T> GetAll();
T GetById(object Id);
T Insert(T obj);
void Delete(object Id);
T Update(T obj);
void Save();
long Count();
}
public class Repository<T> : IRepository<T> where T : class
{
private PegasusPlusEntities context;
private DbSet<T> dbSet;
public Repository()
{
context = new PegasusPlusEntities();
dbSet = context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return dbSet.ToList();
}
public T GetById(object id)
{
return dbSet.Find(id);
}
public T Insert(T obj)
{
dbSet.Add(obj);
Save();
return obj;
}
public void Delete(object id)
{
T entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public void Delete(T entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public T Update(T obj)
{
dbSet.Attach(obj);
context.Entry(obj).State = EntityState.Modified;
Save();
return obj;
}
public long Count()
{
return dbSet.Count();
}
public void Save()
{
try
{
context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
}
}
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (context != null)
{
context.Dispose();
context = null;
}
}
}
}
thanks in advance...
There are a few ways to do this but here is a simple example
Add a method to the current interface to allow for generic search
IEnumerable<T> Search(Expression<Func<T,bool>> predicate);
A simple implementation can look like this
public IEnumerable<T> Search(Expression<Func<T,bool>> predicate) {
return dbSet.Where(predicate).ToList();
}
An example of it in use would be
var repository = new Repository<Person>();
var searchResults = repository.Search(p => p.FirstName == "John" && p.LastName == "Doe");
I want to be able to use a generic service class of type T that will allow me to query the database dynamically. For example. Normally i would do something like this to delete a record
public void Delete(Post post)
{
this._context.Posts.Remove(post);
}
I want to be able to do this
public void Delete(T post)
{
this._context<T>.Remove(post);
}
I found an article here that sort of brushes over it, but if doesnt seem like a clean way to implement it. https://blog.magnusmontin.net/2013/05/30/generic-dal-using-entity-framework/
You need DbContext.Set
https://msdn.microsoft.com/en-us/library/gg679544(v=vs.113).aspx
Returns a non-generic DbSet instance for access to entities of the given type in the context and the underlying store
public void Delete<T>(T post)
where T : class
{
this._context.Set<T>.Remove(post);
}
For later on, you can also query based on:
this._context.Set<T>.AsQueryable().Where(predicate);
In this instance predicate would be a Expression<Func<T, bool>>
So you can have a generic query method:
public IEnumerable<T> Query<T>(Expression<Func<T, bool>> predicate)
where T : class
{
return this._context.Set<T>().AsQueryable().Where(predicate).ToList();
}
... but I'm digressing from the question slightly now!
You can use Generic repository pattern
public class Repository<TEntity> where TEntity : class
{
private dynamic _context;
private DbSet<TEntity> _dbSet;
protected DbContext Context
{
get
{
if (_context == null)
{
_context = DataContextFactory.GetDataContext();
}
return _context;
}
}
protected DbSet<TEntity> DBSet
{
get
{
if (_dbSet == null)
{
_dbSet = this.Context.Set<TEntity>();
}
return _dbSet;
}
}
public virtual IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderExpression = null)
{
return this.GetQuery(predicate, orderExpression).AsEnumerable();
}
public virtual IQueryable<TEntity> GetQuery(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderExpression = null)
{
IQueryable<TEntity> qry = this.DBSet;
if (predicate != null)
qry = qry.Where(predicate);
if (orderExpression != null)
return orderExpression(qry);
return qry;
}
public virtual void Insert<T>(T entity) where T : class
{
DbSet<T> dbSet = this.Context.Set<T>();
dbSet.Add(entity);
}
public virtual void Insert(TEntity entity)
{
this.DBSet.Add(entity);
}
public virtual void Update<T>(T entity) where T : class
{
DbSet<T> dbSet = this.Context.Set<T>();
dbSet.Attach(entity);
this.Context.Entry(entity).State = EntityState.Modified;
}
public virtual void Update(TEntity entity)
{
this.Attach(entity);
this.Context.Entry(entity).State = EntityState.Modified;
}
public virtual void Delete<T>(T entity) where T : class
{
DbSet<T> dbSet = this.Context.Set<T>();
if (this.Context.Entry(entity).State == EntityState.Detached)
dbSet.Attach(entity);
dbSet.Remove(entity);
}
public virtual void Delete(TEntity entity)
{
if (this.Context.Entry(entity).State == EntityState.Detached)
this.Attach(entity);
this.DBSet.Remove(entity);
}
public virtual void Delete<T>(object[] id) where T : class
{
DbSet<T> dbSet = this.Context.Set<T>();
T entity = dbSet.Find(id);
dbSet.Attach(entity);
dbSet.Remove(entity);
}
public virtual void Delete(object id)
{
TEntity entity = this.DBSet.Find(id);
this.Delete(entity);
}
public virtual void Attach(TEntity entity)
{
if (this.Context.Entry(entity).State == EntityState.Detached)
this.DBSet.Attach(entity);
}
public virtual void SaveChanges()
{
this.Context.SaveChanges();
}
}
Usage:
public class Sample
{
public void AddNewPerson(Person newPerson)
{
var personRepo = new Repository<Person>();
personRepo.Insert(newPerson);
personRepo.SaveChanges();
}
public void DeletePerson(int personId)
{
var personRepo = new Repository<Person>();
Person person= personRepo.Find(p => p.Id == personId).SingleOrDefault();
personRepo.Delete(person);
}
}
I am using Autofac for IoC in my project. I have layers for repository, service and web api.
I have class AutofacWebApi in my web api project that I use for registering repository, service and dbcontext.
public class AutofacWebApi
{
public static void Initialize(HttpConfiguration config)
{
Initialize(config, RegisterServices(new ContainerBuilder()));
}
public static void Initialize(HttpConfiguration config, IContainer container)
{
config.DependencyResolver =
new AutofacWebApiDependencyResolver(container);
}
private static IContainer RegisterServices(ContainerBuilder builder)
{
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// registration goes here
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).PropertiesAutowired();
//EF DbContext
builder.RegisterType(typeof(MOCContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork)).InstancePerLifetimeScope();
//Repositories
builder.RegisterGeneric(typeof(GenericRepository<>)).As(typeof(IGenericRepository<>)).InstancePerLifetimeScope();
builder.RegisterType<CityRepository>()
.As<ICityRepository>()
.InstancePerLifetimeScope();
//Services
builder.RegisterType<CityService>().As<ICityService>().InstancePerLifetimeScope();
return builder.Build();
}
}
My web api controler is like this
public class CityController : ApiController
{
readonly ICityService _cityService;
public CityController(ICityService cityService)
{
_cityService = cityService;
}
public IHttpActionResult Get(int id)
{
var result = _cityService.GetById(id);
return Ok("fdsafds");
}
}
When I call method GetById I got null, but I know that the method should return something because if I call the same method from mvc application I got correct result.
CityService
public class CityService : ICityService
{
IUnitOfWork _unitOfWork;
ICityRepository _cityRepository;
public CityService(IUnitOfWork unitOfWork, ICityRepository cityRepository)
: base()
{
_unitOfWork = unitOfWork;
_cityRepository = cityRepository;
}
public CityDTO GetById(int Id)
{
var result=_cityRepository.GetById(Id);
Mapper.CreateMap<City, CityDTO>()
.ForMember(x=>x.Id,m=>m.MapFrom(d=>d.Id));
var map = Mapper.Map<City, CityDTO>(result);
return map;
}
}
ICityService
public interface ICityService
{
CityDTO GetById(int Id);
}
ICityRepository
public interface ICityRepository:IGenericRepository<City>
{
City GetById(int id);
}
CityRepository
public class CityRepository:GenericRepository<City>, ICityRepository
{
public CityRepository(DbContext context)
: base(context)
{
}
public City GetById(int id)
{
var result = Get(x => x.Id == id);
return result;
}
}
IGenericRepository
public interface IGenericRepository<T> where T : BaseEntity
{
IEnumerable<T> GetAll();
IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate);
T Add(T entity);
T Delete(T entity);
void Edit(T entity);
void Save();
}
GenericRepository
public abstract class GenericRepository<T> : IGenericRepository<T>
where T : BaseEntity
{
protected DbContext _entities;
protected readonly IDbSet<T> _dbset;
public GenericRepository(DbContext context)
{
_entities = context;
_dbset = context.Set<T>();
}
public virtual IEnumerable<T> GetAll()
{
return _dbset.AsEnumerable<T>();
}
public T Get(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
T query = _dbset.Where(predicate).SingleOrDefault();
return query;
}
public IEnumerable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
IEnumerable<T> query = _dbset.Where(predicate).AsEnumerable();
return query;
}
public virtual T Add(T entity)
{
return _dbset.Add(entity);
}
public virtual T Delete(T entity)
{
return _dbset.Remove(entity);
}
public virtual void Edit(T entity)
{
_entities.Entry(entity).State = System.Data.Entity.EntityState.Modified;
}
public virtual void Save()
{
_entities.SaveChanges();
}
}
I don't know why method GetById return result null.
Thanks
I currently have this class make up for my Generic Repository
public abstract class RepositoryBase<T> where T : class
{
private readonly ISession session;
public RepositoryBase(ISession session)
{
this.session = session;
this.session.FlushMode = FlushMode.Auto;
}
public void Start()
{
this.session.BeginTransaction();
}
public bool Add(T entity)
{
this.session.Save(entity);
return true;
}
public bool AddAll(IEnumerable<T> items)
{
foreach (T item in items)
{
this.session.Save(item);
}
return true;
}
public bool Update(T entity)
{
this.session.Flush();
this.session.Update(entity);
return true;
}
public bool Delete(T entity)
{
this.session.Delete(entity);
return true;
}
public bool DeleteAll(IEnumerable<T> entities)
{
foreach (T entity in entities)
{
this.Delete(entity);
}
return true;
}
public T GetById(int id)
{
return this.session.Get<T>(id);
}
public T GetById(string id)
{
return this.session.Get<T>(id);
}
public T GetById(long id)
{
return this.session.Get<T>(id);
}
public T GetById(Guid id)
{
return this.session.Get<T>(id);
}
public IQueryable<T> GetAll()
{
return this.session.Query<T>();
}
public T Get(Expression<System.Func<T, bool>> expression)
{
return GetMany(expression).SingleOrDefault();
}
public IQueryable<T> GetMany(Expression<System.Func<T, bool>> expression)
{
return GetAll().Where(expression).AsQueryable();
}
}
When I call the GetById method which takes a string parameter I am met with an exception error that states GetById is expecting type Guid not string. How do I design this method to accept a string parameter?
You can design your class adding another generic parameter for the type of id:
public abstract class Repository<T, TId>
{
public T Get(TId id)
{
}
}
take a look at this https://github.com/sharparchitecture/sharp-architecture/wiki