我是设计模式和依赖注入的新手。我使用本教程来实现我的项目。
使用实体框架、通用存储库模式和工作单元的具有 Web API 的企业级应用程序架构
我有两个 API 控制器:SongController 和 PlaylistController,根据教程,我已经实现到Resolve-dependency-injection一章
当我运行我的应用程序时,我的两个 webapis 1)songcontroller中的http://localhost:49544/api/song与解析器配合得很好 2)http://localhost:49544/api/playlist/8a79e096-052b-4057-9683 -7a7443aa305a返回错误并显示以下消息
exceptionMessage": "依赖项解析失败,类型 = 'MusicCloudWebApi.Controllers.API.PlayListController',名称 = '(none)'。\n在解析时发生异常。\n异常是:InvalidOperationException - 当前类型,MusicCloud。 Services.IPlayListServices,是一个接口,不能构造。您是否缺少类型映射?\n---------------------------------------- ------\n异常发生时,容器为:\r\n Resolving MusicCloudWebApi.Controllers.API.PlayListController,(none)\r\n Resolving parameter 'playListServices' of constructor MusicCloudWebApi.Controllers.API .PlayListController(MusicCloud.Services.IPlayListServices playListServices)\r\n 正在解决 MusicCloud.Services.IPlayListServices,(none)\r\n", "exceptionType": "Unity.Exceptions.
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)\r\n Unity.ResolverPolicy.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context)\r\n lambda_method(Closure , IBuilderContext)\r\n Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicBuildPlanGenerationContext.<>c__DisplayClass16_0.b__0 (IBuilderContext 上下文)\r\n 在 Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicMethodBuildPlan.BuildUp(IBuilderContext 上下文)\r\n 在 Unity.ObjectBuilder.Strategies.BuildPlanStrategy.PreBuildUp(IBuilderContext 上下文)\r\n 在 Unity.Container .StrategyChain.BuildUp(IBuilderContext builderContext)\r\n 在 Unity.Policy.BuildPlanPolicyExtensions.ExecuteBuildUp(IBuildPlanPolicy 策略,IBuilderContext 上下文)\r\n 在 Unity.UnityContainer.BuildUp(类型 typeToBuild,现有对象,字符串名称,ResolverOverride[]解析器覆盖)"} } }
数据库表中的 userId 是 nvarchar(128) 类型
我尚未实现身份验证,但将表中的值作为参数硬编码到 webapi。
错误有什么问题?
解析器项目有以下接口和类
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 项目解决方案中,在 global.asax(UnityConfig.RegisterComponents();) 处调用了以下类 UnityConfig
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>();
}
}
}
播放列表控制器(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 中,我有一个实现 PlayListServices 的接口 IPlayListServices
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;
}
}
}
}