asp.net универсальный репозиторий webapi и внедрение зависимостей с помощью resolver выдает ошибку
Я новичок в разработке шаблонов и внедрения зависимостей. Я использовал этот учебник для реализации моего проекта.
Решение, реализующее описанный выше шаблон дизайна учебника и внедрение зависимостей с помощью IOC
У меня есть два API-контроллера:SongController и PlaylistController, и, согласно учебному пособию, я реализовал до главы Resolve-зависимость-инъекция
Когда я запускаю свое приложение, мои два webapis 1) http://localhost:49544/api/song в songcontroller отлично работают с распознавателем 2) http://localhost:49544/api/playlist/8a79e096-052b-4057-9683-7a7443aa305a возвращает ошибку со следующим сообщением
{ "message": "Произошла ошибка.", "exceptionMessage": "Произошла ошибка при попытке создать контроллер типа 'PlayListController'. Убедитесь, что контроллер имеет открытый конструктор без параметров.", "exceptionType": "System.InvalidOperationException", "stackTrace": " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(запрос HttpRequestMessage, HttpControllerDescriptor controllerDescriptor, тип controllerType)\r\n.ControlControllerControl Запрос HttpRequestMessage)\r\n в System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()", "innerException": { "message": " Произошла ошибка. "," ExceptionMessage ":" Разрешение сбой зависимости, type = 'MusicCloudWebApi.Controllers.API.PlayListController', name = '(none)'.\n Ошибка произошла во время: при разрешении. \ nException is: InvalidOperationException - Текущий тип, MusicCloud.Services.IPlayListServices, является интерфейсом и не может быть со nstructed. Вам не хватает сопоставления типов?\ N ----------------------------------------- ------ \ n В момент исключения контейнер был: \r\n Разрешить MusicCloudWebApi.Controllers.API.PlayListController,(нет)\r\n Разрешить параметр 'playListServices' конструктора MusicCloudWebApi.Controllers.API.PlayListController(MusicCloud.Services.IPlayListServices playListServices)\r\n Разрешение MusicCloud.Services.IPlayListServices,(нет)\r\n", "exceptionType": "Unity.Exceptions.ResolutionFailedException", "stackTrace. At "." UnityContainer.BuildUp(Тип typeToBuild, Существующий объект, Имя строки, ResolverOverride [] resolverOverrides)\r\n в Unity.UnityContainer.Resolve (Тип тип, Строковое имя, ResolverOverride [] resolverOverrides)\r\n в Unity.UnityRtainerEx (Контейнер IUnityContainer, Тип t, ResolverOverride [] переопределяет)\r\n в Unity.WebApi.UnityDependencyScope.GetService (Тип serviceType)\r\n в System.Web.Http.Dispatcher.DefaultHttpControllerActivator.RetInstance Запрос HttpRequestMessage, Type controllerType, Func
1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)", "innerException": { "message": "An error has occurred.", "exceptionMessage": "The current type, MusicCloud.Services.IPlayListServices, is an interface and cannot be constructed. Are you missing a type mapping?", "exceptionType": "System.InvalidOperationException", "stackTrace": " at Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicMethodConstructorStrategy.ThrowForAttemptingToConstructInterface(IBuilderContext context)\r\n at lambda_method(Closure , IBuilderContext )\r\n at Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicBuildPlanGenerationContext.<>c__DisplayClass16_0.<GetBuildMethod>b__0(IBuilderContext context)\r\n at Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)\r\n at Unity.ObjectBuilder.Strategies.BuildPlanStrategy.PreBuildUp(IBuilderContext context)\r\n at Unity.Container.StrategyChain.BuildUp(IBuilderContext builderContext)\r\n at Unity.Policy.BuildPlanPolicyExtensions.ExecuteBuildUp(IBuildPlanPolicy policy, IBuilderContext context)\r\n at Unity.ObjectBuilder.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey, Action
1 childCustomizationBlock. (Контекст IBuilderContext)\r\n в Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicMethodBuildPlan.BuildUp (Контекст IBuilderContext)\r\n в Unity.ObjectBuilder.Strategies.BuildPlanStrategy.PertainUntity.Inte.StrategyChain.BuildUp(IBuilderContext builderContext)\r\n в Unity.Policy.BuildPlanPolicyExtensions.ExecuteBuildUp(IBuildPlanPolicy, контекст IBuilderContext)\r\n в Unity.UnityContainer, тип-объекта-объекта-наследования resolverOverrides)" } } }
ИД пользователя в таблице базы данных имеет тип nvarchar(128)
Я еще не реализовал аутентификацию, но жестко запрограммировал значение из таблицы в качестве параметра для webapi.
в чем проблема с ошибкой?
Исследователь проекта Resolver
Проект Resolver имеет следующие интерфейсы и класс
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Resolver
{
public interface IComponent
{
void SetUp(IRegisterComponent registerComponent);
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web;
using Unity;
using Unity.Lifetime;
namespace Resolver
{
public static class ComponentLoader
{
public static void LoadContainer(IUnityContainer container, string path, string pattern)
{
var dirCat = new DirectoryCatalog(path, pattern);
var importDef = BuildImportDefinition();
try
{
using (var aggregateCatalog = new AggregateCatalog())
{
aggregateCatalog.Catalogs.Add(dirCat);
using (var componsitionContainer = new CompositionContainer(aggregateCatalog))
{
IEnumerable<Export> exports = componsitionContainer.GetExports(importDef);
IEnumerable<IComponent> modules =
exports.Select(export => export.Value as IComponent).Where(m => m != null);
var registerComponent = new RegisterComponent(container);
foreach (IComponent module in modules)
{
module.SetUp(registerComponent);
}
}
}
}
catch (ReflectionTypeLoadException typeLoadException)
{
var builder = new StringBuilder();
foreach (Exception loaderException in typeLoadException.LoaderExceptions)
{
builder.AppendFormat("{0}\n", loaderException.Message);
}
throw new TypeLoadException(builder.ToString(), typeLoadException);
}
}
private static ImportDefinition BuildImportDefinition()
{
return new ImportDefinition(
def => true, typeof(IComponent).FullName, ImportCardinality.ZeroOrMore, false, false);
}
}
internal class RegisterComponent : IRegisterComponent
{
private readonly IUnityContainer _container;
public RegisterComponent(IUnityContainer container)
{
this._container = container;
//Register interception behaviour if any
}
public void RegisterType<TFrom, TTo>(bool withInterception = false) where TTo : TFrom
{
if (withInterception)
{
//register with interception
}
else
{
this._container.RegisterType<TFrom, TTo>();
}
}
public void RegisterTypeWithControlledLifeTime<TFrom, TTo>(bool withInterception = false) where TTo : TFrom
{
this._container.RegisterType<TFrom, TTo>(new ContainerControlledLifetimeManager());
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Resolver
{
/// <summary>
/// Responsible for registering types in unity configuration by implementing IComponent
/// </summary>
public interface IRegisterComponent
{
/// <summary>
/// Register type method
/// </summary>
/// <typeparam name="TFrom"></typeparam>
/// <typeparam name="TTo"></typeparam>
/// <param name="withInterception"></param>
void RegisterType<TFrom, TTo>(bool withInterception = false) where TTo : TFrom;
/// <summary>
/// Register type with container controlled life time manager
/// </summary>
/// <typeparam name="TFrom"></typeparam>
/// <typeparam name="TTo"></typeparam>
/// <param name="withInterception"></param>
void RegisterTypeWithControlledLifeTime<TFrom, TTo>(bool withInterception = false) where TTo : TFrom;
}
}
в решении проекта MusicWebAPI следующий класс UnityConfig вызывается по адресу global.asax(UnityConfig.RegisterComponents();)
using MusicCloud.Model;
using MusicCloud.Services;
using Resolver;
using System.Web.Http;
using System.Web.Mvc;
using Unity;
using Unity.Lifetime;
using Unity.WebApi;
namespace MusicCloudWebApi
{
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = BuildUnityContainer();
// System.Web.Mvc.DependencyResolver.SetResolver(new UnityDependencyResolver(container));
System.Web.Mvc.DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
// register dependency resolver for WebAPI RC
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
// Create the depenedency resolver.
//var resolver = new AutofacWebApiDependencyResolver(container);
// Configure Web API with the dependency resolver.
//GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
// container.RegisterType<IProductServices, ProductServices>().RegisterType<UnitOfWork>(new HierarchicalLifetimeManager());
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container)
{
//Component initialization via MEFE:\Susana\Portfolio\MusicCloud\MusicCloud\MusicCloudWebApi\bin\MusicCloudWebApi.dll
ComponentLoader.LoadContainer(container, ".\\bin", "MusicCloudWebApi.dll");
ComponentLoader.LoadContainer(container, ".\\bin", "MusicCloud.Services.dll");
// container.Register<DashboardDbContext>(
// new InjectionFactory(c => new DashboardDbContext()));
}
}
internal class AutofacWebApiDependencyResolver
{
private IUnityContainer container;
public AutofacWebApiDependencyResolver(IUnityContainer container)
{
this.container = container;
}
}
}
В MusicCloud.Model у меня есть имя класса DependencyResolver
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.Composition;
using Resolver;
using MusicCloud.Repository;
using System.Data.Entity;
using MusicCloud.Model;
namespace MusicCloud.Model
{
/// <summary>
/// a) Export in System.ComponentModel.Composition
/// b)IComponent in Resolver in Resolver Project
/// </summary>
[Export(typeof(IComponent))]
public class DependencyResolver : IComponent
{
public void SetUp(IRegisterComponent registerComponent)
{
registerComponent.RegisterType<IUnitOfWork, UnitOfWork>();
}
}
}
playlistcontroller (API)
[System.Web.Http.HttpGet]
//// GET api/playlist/abc
public HttpResponseMessage GetPlayLists(string userId)
{
userId = "8a79e096-052b-4057-9683-7a7443aa305a";
var playLists = _playListServices.GetAllPlayLists(userId);
if (playLists != null)
{
var playListEntities = playLists as List<PlayListEntity> ?? playLists.ToList();
if (playListEntities.Any())
return Request.CreateResponse(HttpStatusCode.OK, playListEntities);
}
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "PlayLists not found");
}
В MusicCloud.Services у меня есть интерфейс IPlayListServices, который реализует PlayListServices
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MusicCloud.Entities;
using MusicCloud.Model;
using AutoMapper;
using MusicCloud.Model.EFModel;
using System.Transactions;
namespace MusicCloud.Services
{
public class PlayListServices : IPlayListServices
{
private readonly UnitOfWork _unitOfWork;
/// <summary>
/// Public constructor.
/// </summary>
//public PlayListServices()
//{
// _unitOfWork = new UnitOfWork();
//}
public PlayListServices(UnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
/// <summary>
/// Fetches playList details by id
/// </summary>
/// <param name="playListId"></param>
/// <returns></returns>
public PlayListEntity GetPlayListById(int playListId)
{
var playList = _unitOfWork.PlayListRepository.GetByID(playListId);
if (playList != null)
{
// Mapper.CreateMap<Song, SongEntity>();
Mapper.Initialize(cfg =>
{
cfg.CreateMap<PlayList, PlayListEntity>();
//Mapper.Map<Song, SongEntity>();
});
var playListModel = Mapper.Map<PlayList, PlayListEntity>(playList);
return playListModel;
}
return null;
}
/// <summary>
/// Fetches all the songs.
/// </summary>
/// <returns></returns>
public IEnumerable<PlayListEntity> GetAllPlayLists(string userId)
// public PlayListEntity GetAllPlayLists(int userId)
{
var playLists = _unitOfWork.PlayListRepository
.GetAllSongs(x =>
x.PlayListSongs.Select(report => report.UserId==userId)).ToList();
if (playLists.Any())
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<PlayList, PlayListEntity>();
});
var playListsModel = Mapper.Map<List<PlayList>, List<PlayListEntity>>(playLists);
return playListsModel;
}
return null;
}
/// <summary>
/// Creates a product
/// </summary>
/// <param name="productEntity"></param>
/// <returns></returns>
public int CreatePlaylist(PlayListEntity playListEntity)
{
///remove
var userId = "1";
using (var scope = new TransactionScope())
{
var playList = new PlayList
{
Name = playListEntity.Name,
CreatedDate= playListEntity.CreatedDate,
ModifiedDate=playListEntity.ModifiedDate
};
_unitOfWork.PlayListRepository.Insert(playList);
_unitOfWork.Save();
scope.Complete();
return playList.Id;
}
}
}
}
1 ответ
@NightOwl888 Спасибо за подсказку о разрешении зависимостей. Я нашел, что вызывает проблему. Я пропустил, чтобы зарегистрировать IplaylistServices в dependencyresolver.cs
registerComponent.RegisterType<IPlayListServices, PlayListServices>();