Autofac and ASP .Net MVC 4 Web API - asp.net-mvc-4

I am using Autofac for IoC in my ASP .Net MVC 4 project. Autofac is having some trouble initializing the repository and passing it to the API Controller.
I am sure I am missing something in my configuration.
Here is the error I get when I navigate to: https://localhost:44305/api/integration
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'
on type 'EL.Web.Controllers.API.IntegrationController' can be invoked with
the available services and parameters: Cannot resolve parameter
'EL.Web.Infrastructure.IRepository`1[EL.Web.Models.Integration] repository' of
constructor 'Void .ctor(EL.Web.Infrastructure.IRepository`1[EL.Web.Models.Integration])'.
</ExceptionMessage>
<ExceptionType>Autofac.Core.DependencyResolutionException</ExceptionType>
<StackTrace>
at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
at Autofac.Core.Resolving.InstanceLookup.Execute()
at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType)
at Autofac.Integration.WebApi.AutofacWebApiDependencyScope.GetService(Type serviceType)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
</StackTrace>
</Error>
Here are some relevant bits of code:
IoC Bootstrapper:
public static class Bootstrapper
{
public static void Initialize()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.Register(x => new SharePointContext(HttpContext.Current.Request)).As<ISharePointContext>().SingleInstance();
builder.RegisterType<SharePointRepository<IEntity>>().As<IRepository<IEntity>>();
builder.RegisterType<SharePointContextFilter>().SingleInstance();
builder.RegisterFilterProvider();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
}
IRepository:
public interface IRepository<T>
{
void Add(T entity);
void Delete(int id);
IEnumerable<T> Find(Expression<Func<T, bool>> filter = null);
void Update(int id, T entity);
}
SharePointRepository:
internal class SharePointRepository<T> : IRepository<T> where T : IEntity
{
private readonly ISharePointContext _context;
private readonly string _listName;
internal SharePointRepository(ISharePointContext context)
{
_context = context;
object[] attributes = typeof (T).GetCustomAttributes(typeof (SharePointListAttribute), false);
if (!attributes.Any())
{
throw new Exception("No associated SharePoint list defined for " + typeof (T));
}
_listName = ((SharePointListAttribute) attributes[0]).ListName;
}
public void Add(T entity)
{
throw new NotImplementedException();
}
public void Delete(int id)
{
throw new NotImplementedException();
}
public IEnumerable<T> Find(Expression<Func<T, bool>> filter)
{
throw new NotImplementedException();
}
public void Update(int id, T entity)
{
throw new NotImplementedException();
}
}
IntegrationController:
public class IntegrationController : ApiController
{
private readonly IRepository<Integration> _repository;
public IntegrationController(IRepository<Integration> repository)
{
_repository = repository;
}
public void Delete(Guid integrationId)
{
_repository.Delete(Get(integrationId).Id);
}
public IEnumerable<Integration> Get()
{
return _repository.Find();
}
public Integration Get(Guid integrationId)
{
return _repository.Find(i => i.IntegrationId == integrationId).FirstOrDefault();
}
public void Post([FromBody] Integration integration)
{
_repository.Add(integration);
}
public void Put(Guid integrationId, [FromBody] Integration integration)
{
_repository.Update(Get(integrationId).Id, integration);
}
}
IEntity:
internal interface IEntity
{
int Id { get; }
}
Entity:
public abstract class Entity : IEntity
{
protected Entity(int id)
{
Id = id;
}
public int Id { get; private set; }
}
Integration:
[SharePointList("Integrations")]
public class Integration : Entity
{
public Integration(int id) : base(id)
{
}
public string ApiUrl { get; set; }
public bool DeletionAllowed { get; set; }
public Guid IntegrationId { get; set; }
public string Key { get; set; }
public string List { get; set; }
public bool OutgoingAllowed { get; set; }
public string RemoteWeb { get; set; }
public string Web { get; set; }
}

You have registered your IRepository wrong. With the line:
builder.RegisterType<SharePointRepository<IEntity>>().As<IRepository<IEntity>>();
You told Autofac that whenever somebody will request an IRepository<IEntity> give them a SharePointRepository<IEntity>, but you are requesting a concrete IRepository<Integration> so you get an exception.
What you need is the open generic registration feature of Autofac. So change your registration to:
builder.RegisterGeneric(typeof(SharePointRepository<>))
.As(typeof(IRepository<>));
It will work as you would expect you when you ask for a IRepository<Integration> it will give a SharePointRepository<Integration>.
You also have a second unrelated problem: your SharePointRepository has only an internal constructor.
Autofac by default only looks for public constructors so you either change your constructor and class to public or you need to tell to Autofac to look for NonPublic constructors with the FindConstructorsWith method:
builder
.RegisterType<SharePointRepository<IEntity>>()
.FindConstructorsWith(
new DefaultConstructorFinder(type =>
type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)))
.As<IRepository<IEntity>>();

Related

How to implement Service inherit from generic repository?

I work on asp.net core mvc blazor application , I have issue I can't implement service inherit from generic repository .
meaning how to inherit from IRepository to get functions below on class server names service :
Insert
Update
GetById
GetList
GetListAsync
Interface generic repository
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
public interface IRepository<TEntity> where TEntity : class
{
Task<int> Count(Expression<Func<TEntity, bool>> where);
TEntity GetByID(object id);
TEntity Insert(TEntity entity);
void Update(TEntity entityToUpdate);
Task<ICollection<TType>> Get<TType>(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, TType>> select) where TType : class;
Task<bool> Any(Expression<Func<TEntity, bool>> where);
TEntity GetFirst(Expression<Func<TEntity, bool>> where);
TEntity Single(Expression<Func<TEntity, bool>> where);
Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> where);
List<TEntity> GetList(Expression<Func<TEntity, bool>> where);
Task<bool> UpdateBasedOnCondition(Expression<Func<TEntity, bool>> where, Action<TEntity> select);
void Save();
}
class that implement interface as below :
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using UC.AppRepository.Core;
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
internal AppsRepositoryDBContext _context;
internal DbSet<TEntity> dbSet;
public BaseRepository(AppsRepositoryDBContext context)
{
_context = context;
this.dbSet = _context.Set<TEntity>();
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
public virtual TEntity Insert(TEntity entity)
{
var result = dbSet.AddAsync(entity).Result.Entity;
Save();
return result;
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
_context.Entry(entityToUpdate).State = EntityState.Modified;
}
public virtual async Task<bool> UpdateBasedOnCondition(Expression<Func<TEntity, bool>> where, Action<TEntity> select)
{
try
{
var ListOfRecord = await dbSet.Where(where).ToListAsync();
if (null != ListOfRecord && ListOfRecord.Count > 0)
{
ListOfRecord.ForEach(select);
// Save();
await _context.SaveChangesAsync();
return true;
}
return false;
}
catch (Exception ex)
{
return false;
throw;
}
}
public async Task<ICollection<TType>> Get<TType>(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, TType>> select) where TType : class
{
if(where == null)
{
return await dbSet.Select(select).ToListAsync();
}
return await dbSet.Where(where).Select(select).ToListAsync();
}
public async Task<int> Count(Expression<Func<TEntity, bool>> where)
{
return await dbSet.Where(where).CountAsync();
}
public async virtual Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> where)
{
// var test = dbSet.Where(where).ToList();
return await dbSet.Where(where).ToListAsync();
}
public virtual List<TEntity> GetList(Expression<Func<TEntity, bool>> where)
{
return dbSet.Where(where).ToList();
}
public async Task<bool> Any(Expression<Func<TEntity, bool>> where)
{
return await dbSet.AnyAsync(where);
}
public TEntity GetFirst(Expression<Func<TEntity, bool>> where)
{
return dbSet.FirstOrDefault(where);
}
public TEntity Single(Expression<Func<TEntity, bool>> where)
{
return dbSet.Single(where);
}
public void Save()
{
try
{
_context.SaveChanges();
}
catch (Exception ex)
{
throw;
}
}
}
so I have class ServerNameService and class interface IserverNamesService
I need to implement insert,update,selectById,selectall functions for server name models
from base repository
public class ServerNameService:IRepository
{
// what i write here
}
public interface IserverNamesService:IRepository
{
// what i write here
}
public class ServerNames
{
[Key]
public int ServerID { get; set; }
public string Server_Name{ get; set; }
public string Server_Type { get; set; }
public string Operating_System { get; set; }
public string Version { get; set; }
public bool IsActive { get; set; }
}
I have issue I can't implement service inherit from generic repository.I have class ServerNameService and class interface IserverNamesService I need to implement insert,update,selectById,selectall functions for server name models from base repository
Well, to directly answer your question, to implement your ServerNameService which derived from IRepository that would would be as following:
IserverNamesService:
public interface IserverNamesService : IRepository<ServerNames>
{
}
Note: Keep it empty because we will use of IRepository and BaseRepository in ServerNamesService class to implement its members.
ServerNamesService:
public class ServerNamesService : BaseRepository<ServerNames>, IserverNamesService
{
public ServerNamesService(ApplicationDbContext context) : base(context)
{
}
public override ServerNames GetByID(object id)
{
return _context.ServerNames.Where(sn => sn.ServerID == (int)id).FirstOrDefault();
}
}
Controller:
[Route("api/[controller]")]
[ApiController]
public class ServerNamesServiceController : ControllerBase
{
private readonly IserverNamesService _serverNamesService;
public ServerNamesServiceController(IserverNamesService namesService)
{
_serverNamesService = namesService;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetById(object id)
{
var item = _serverNamesService.GetByID(id);
if (item == null)
return NotFound();
return Ok(item);
}
}
Program.cs:
builder.Services.AddScoped<IserverNamesService, ServerNamesService>();
Note: Register your ServerNamesService class in your program.cs
UnitOfWork Pattern Implementation:
As long your application would continue evolving and there would be ton of service class, in that scenario, you have to introduce lot of service in your controller. But if you would like to handle those smoothly, you could use UnitOfWork pattern which would contain all of your service together.
Interface:
public interface IUnitOfWork
{
IserverNamesService ServerNamesService { get; }
Task CompleteAsync();
}
Implementation:
public class UnitOfWork : IUnitOfWork, IDisposable
{
private readonly ApplicationDbContext _context;
public IserverNamesService ServerNamesService { get; private set; }
public UnitOfWork(ApplicationDbContext context)
{
_context = context;
ServerNamesService = new ServerNamesService(context);
}
public async Task CompleteAsync()
{
await _context.SaveChangesAsync();
}
public void Dispose()
{
_context.Dispose();
}
}
Controller:
[Route("api/[controller]")]
[ApiController]
public class ServerNamesServiceController : ControllerBase
{
private readonly IUnitOfWork _unitOfWork;
public ServerNamesServiceController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetById(object id)
{
var item = _unitOfWork.ServerNamesService.GetByID(id);
if (item == null)
return NotFound();
return Ok(item);
}
}
Output:
Note: If you would like to know more details on repository pattern you could check our official document here and working sample here.
You should pass your Entity as generic type to IRepository in IServerNamesService, and then inheritance ServerNameService from IServerNamesService.
public interface IServerNamesService:IRepository<ServerNames>
{
// your methods interface
}
public class ServerNameService:IServerNamesService{
private readonly IRepository<ServerNames> _repository;
public class ServerNameService(IRepository<ServerNames> repository)
{
_repository = repository;
}
//body of your methods
}

ASP.NET Core: validation attributes are ignored on fields defined in children types

My ASP.NET Core 2.1 API exposes the following input DTO in a POST endpoint:
[Route("test")]
[ApiController]
public class TestController : ControllerBase
{
[HttpPost("endpoint")]
public async Task<IActionResult> Post([Required]MyDTO dto)
{
// Some code
}
}
public class MyDTO
{
[JsonProperty("foo")]
[Required]
public Foo Foo { get; set; }
}
The Foo class is defined as follow:
[JsonConverter(typeof(FooConverter))]
public abstract class Foo
{
[JsonProperty("foo_type")]
[Required]
public string FooType { get; set; }
}
The FooConverter class is able to instantiate the right implementation based on the foo_type field:
public class FooConverter : JsonConverter<Foo>
{
public override bool CanRead => true;
public override bool CanWrite => false;
public override Foo ReadJson(JsonReader reader, Type objectType, Foo existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
Foo target = this.CreateFoo(jObject);
serializer.Populate(jObject.CreateReader(), target);
return target;
}
public override void WriteJson(JsonWriter writer, Foo value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
private Foo CreateFoo(JObject jObject)
{
string fooType = jObject.Value<string>("foo_type");
switch (fooType)
{
case "foo1":
return new Foo1();
case "foo2":
return new Foo2();
default:
throw new JsonSerializationException($"Invalid 'foo_type' '{fooType}'");
}
}
}
Here is one of the implementations of the Foo abstract class:
public class Foo1 : Foo
{
[JsonProperty("bar")]
[Required]
public string Bar { get; set; }
}
My problem is that the [Required] attribute on Foo1.Bar is ignored by ASP.NET validation, even though the [Required] attribute on Foo.FooType works as expected. How can I automatically validate the fields defined in the implementation types so that it works the same as with other fields?
Replace:
var jObject = JObject.Load(reader);
with:
JToken jObject = JToken.ReadFrom(reader);

Invalid column name 'EmailAddress' when using generic repository, but works fine with context

Getting the mentioned error when trying to do a GetAll on accounts. It works fine if I go directly to the dbcontext, but gives me the error if I try to work with the repo. I have about 20 others that use just the generic repo and are working great. Because I have additional actions for Accounts, I have created its own repository that implements the generic. I also have several others that work like this and have no problem. The problem is specific to the accounts.
Database of course does have the EmailAddress column, since I can return it if I use dbcontext from the controller instead of the repo.
Any help would be much appreciated.
AccountsController:
public class AccountsController : ControllerBase
{
private readonly AccountRepository _repo;
public AccountsController(DatabaseContext context)
{
_repo = new AccountRepository(context);
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Account>>> GetAccount()
{
// return _context.Account.ToListAsync(); works fine if _context is defined
var accounts = await _repo.GetAll();
if (accounts == null)
return NoContent();
return Ok(accounts); // Gives invalid column error
}
[HttpGet("getaccount")]
public async Task<ActionResult<Account>> GetCurrentAccount()
{
var account = await _repo.GetCurrentAccount(HttpContext.User.Identity.Name);
if (account == null)
{
return NotFound();
}
return account; // Works fine
}
}
Account:
public partial class Account
{
public string Name { get; set; }
public string RefId { get; set; }
public string Position { get; set; }
public bool IsActive { get; set; }
public string EmailAddress { get; set; }
[Key]
public string UserId { get; set; }
}
IAccountRepository:
public interface IAccountRepository : IRepository<Account>
{
Task<Account> GetCurrentAccount(string emailAddress);
}
AccountRepository:
public class AccountRepository : Repository<Account>, IAccountRepository
{
private DatabaseContext _context;
public AccountRepository(DatabaseContext context)
{
_context = context;
}
public async Task<Account> GetCurrentAccount(string emailAddress)
{
var account = await _context.Account
.Where(a => a.EmailAddress == emailAddress)
.FirstOrDefaultAsync();
return account; // this works just fine, and returns with EmailAddress
}
}
IRepository (generic):
public interface IRepository<T>
{
Task<IEnumerable<T>> GetAll();
Task<T> GetById(object id);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
Task<bool> Save();
}
Repository (generic):
public class Repository<T> : IRepository<T> where T : class
{
private DatabaseContext _context;
public Repository()
{
_context = new DatabaseContext();
}
public Repository(DatabaseContext context)
{
_context = context;
}
public void Add(T obj)
{
_context.Set<T>().Add(obj);
}
public void Delete(T entity)
{
_context.Set<T>().Remove(entity);
}
public async Task<IEnumerable<T>> GetAll()
{
return await _context.Set<T>().ToListAsync();
}
public async Task<T> GetById(object id)
{
return await _context.Set<T>().FindAsync(id);
}
public void Update(T obj)
{
_context.Set<T>().Update(obj);
}
public async Task<bool> Save()
{
try
{
await _context.SaveChangesAsync();
}
catch (Exception)
{
return false;
}
return true;
}
}
EDIT
I should mention that EmailAddress was added to the database via EF migration.

IUrlHelper not being resolved in RC2

While migrating from ASP.NET Core RC1 to RC2 my TagHelpers do not resolve the injected IUrlHelpers.
[HtmlTargetElement("usermenulink", Attributes = "controller-name, action-name, menu-text, menu-item, active-item")]
public class UserMenuItemTagHelper : TagHelper
{
public IUrlHelper _UrlHelper { get; set; }
public UserMenuItemTagHelper(IUrlHelper urlHelper)
{
_UrlHelper = urlHelper;
}
//... abbreviated
}
Instead I get an exception:
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Mvc.IUrlHelper' while attempting to activate '...TagHelpers.UserMenuItemTagHelper'.
Any ideas?
I found out myself that with RC2 you have to (or can) inject an IUrlHelperFactory and get an UrlHelper instance of this.
public class UserMenuLinkTagHelper : TagHelper
{
[ViewContext]
public ViewContext ViewContext { get; set; }
public IUrlHelperFactory _urlHelperFactory { get; set; }
public UserMenuLinkTagHelper(IUrlHelperFactory urlHelperFactory)
{
_urlHelperFactory = urlHelperFactory;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var urlHelper = _urlHelperFactory.GetUrlHelper(ViewContext);
string menuUrl = urlHelper.Action(ActionName, ControllerName);
//...
}
}
Here is the example of the current implementation of the Mvc team:
https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.TagHelpers/ImageTagHelper.cs

wcf Service Known type attribute question

i wanna add a service behavior(or anything u'll suggest) that will automatically insert the types from dll to the service known types of the service
is it possible? how?
Known type attributes are passed to the DataContractSerializer constructor. You can customize the way this serializer is instantiated and provide the known types to the constructor of the serializer by reflecting over your assemblies and finding all types that derive from a base class.
Here's a sample code (not tested):
[ServiceContract]
public interface FooContract
{
[OperationContract]
[KnownTypesDataContractFormat(typeof(SomeBaseType))]
void MyOperation(SomeBaseType arg);
}
public class KnownTypesDataContractFormatAttribute : Attribute, IOperationBehavior
{
public Type BaseType { get; private set; }
public KnownTypesDataContractFormatAttribute(Type baseType)
{
BaseType = baseType;
}
public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{ }
public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
{
IOperationBehavior innerBehavior = new KnownTypesDataContractSerializerOperationBehavior(description, BaseType);
innerBehavior.ApplyClientBehavior(description, proxy);
}
public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
{
IOperationBehavior innerBehavior = new KnownTypesDataContractSerializerOperationBehavior(description, BaseType);
innerBehavior.ApplyDispatchBehavior(description, dispatch);
}
public void Validate(OperationDescription description)
{ }
}
public class KnownTypesDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public Type BaseType { get; private set; }
public KnownTypesDataContractSerializerOperationBehavior(OperationDescription operationDescription, Type baseType) : base(operationDescription)
{
BaseType = baseType;
}
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes);
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes);
}
private IEnumerable<Type> GetKnownTypes()
{
// Try to find all types that derive from BaseType in the
// executing assembly and add them to the knownTypes collection
return
from type in Assembly.GetExecutingAssembly().GetTypes()
where type != BaseType && BaseType.IsAssignableFrom(type)
select type;
}
}