2016-09-05 2 views
2

Я получаю это исключение при отладке кода:Unity отображение интерфейса исключение в Web API

Resolution of the dependency failed, type = "Aqueduct.Interfaces.IMasterDataClient", name = "MDS". 
Exception occurred while: while resolving. 
Exception is: InvalidOperationException - The current type, 
Aqueduct.Interfaces.IMasterDataClient, is an interface and cannot be constructed. Are you missing a type mapping? 

На момент исключения, код контейнера был:

Resolving Aqueduct.Interfaces.IMasterDataClient,MDS

Unity.config :

public static class UnityConfig 
{ 
    public static void RegisterComponents() 
    { 
     var container = new UnityContainer(); 
     IUnityContainer myContainer = new UnityContainer(); 

     // register all your components with the container here 
     // it is NOT necessary to register your controllers 

     // e.g. container.RegisterType<ITestService, TestService>(); 
     myContainer.RegisterType<IMasterDataClient, MasterDataClient>("MDS"); 
     myContainer.RegisterType<ILinksManager, LinksManager>("LDS"); 
     GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container); 
    } 
} 

Web контроллер Api:

using (var container = new UnityContainer()) 
{ 
     container.Resolve<IMasterDataClient>("MDS"); 
     container.Resolve<ILinksManager>("LDS"); 
} 

MasterDataClient интерфейса Реализация класса:

public class MasterDataClient : HalClient, IMasterDataClient, IHalClient, ICrestaClient 
{ 
    public MasterDataClient(IApiClient apiClient, IUriDispenser dispenser); 
} 

ответ

2

У вас есть три проблемы здесь.

Задача 1. Вы создаете новый контейнер:

using (var container = new UnityContainer()) 
{ 
     container.Resolve<IMasterDataClient>("MDS"); 
     container.Resolve<ILinksManager>("LDS"); 
} 

Это container будет пустым и иметь 0 регистраций. Это не тот контейнер, на который вы сделали регистрацию. Существует несколько способов решить эту проблему:

Проблема 1 - Решение 1: Не вводите контейнер. Ввести зависимости. Вместо того, чтобы использовать контейнер, вы должны вводить свои зависимости непосредственно к контроллеру:

public class MyApiController : ApiController 
{ 
    IMasterDataClient _masterDataClient; 
    ILinksManager _linksManager 


    public MyApiController(IMasterDataClient masterDataClient, ILinksManager linksManager) 
    { 
     _masterDataClient = masterDataClient; 
     _linksManagerlinksManager; 
    } 
} 

Таким образом, вы можете избежать службы локатора-модель и вашу зависимость для самого контейнера. Если вы используете именованные регистрации, вам может понадобиться использовать атрибут Dependency.

With Unity how do I inject a named dependency into a constructor?

Задача 1 - Решение 2: Вводите свой контейнер, а не создавать новый. Если вам действительно нужен ваш контроллер по какой-то причине, вы должны попытаться ввести его вместо этого. Таким образом вы получите тот же контейнер, что и для ваших регистраций.

public class MyApiController : ApiController 
{ 
    IUnityContainer _container; 


    public MyApiController(IUnityContainer container) 
    { 
     _container = container; 
    } 
} 

Задача 1 - Решение 3: Держите статическую ссылку на свой контейнер. В качестве последнего средства вы можете сохранить свой контейнер как статический экземпляр.

public static class IocContainer 
{ 
    private static readonly Lazy<IUnityContainer> Container = new Lazy<IUnityContainer>(() => 
    { 
     var container = new UnityContainer(); 
     return container; 
    }); 

    public static IUnityContainer Instance 
    { 
     get { return Container.Value; } 
    } 
} 

И в вашей регистрации:

public static class UnityConfig 
{ 
    public static void RegisterComponents() 
    { 
     var container = IocContainer.Instance; 

     // register all your components with the container here 
     // it is NOT necessary to register your controllers 

     // e.g. container.RegisterType<ITestService, TestService>(); 
     myContainer.RegisterType<IMasterDataClient, MasterDataClient>("MDS"); 
     myContainer.RegisterType<ILinksManager, LinksManager>("LDS"); 
     GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container); 
    } 
} 

Использование:

IocContainer.Instance.Resolve<IMasterDataClient>("MDS"); 

Задача 2.Кажется, вы не регистрируете зависимости для MasterDataClient.

Имеет зависимости от IApiClient и IUriDispenser. Они также должны быть зарегистрированы.

Задача 3. Вы назначаете распознаватель зависимость к неправильному контейнера

Вы в настоящее время создать два контейнера - myContainer и container. Вы делаете регистрацию в одном контейнере, а затем используете другой номер DependencyResolver. Вы можете решить эту проблему, удалив myContainer и используйте только container. В противном случае вы не сможете использовать свои регистрации в Web Api.

public static class UnityConfig 
{ 
    public static void RegisterComponents() 
    { 
     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<IMasterDataClient, MasterDataClient>("MDS"); 
     container.RegisterType<ILinksManager, LinksManager>("LDS"); 
     GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container); 
    } 
} 

Update:

Я не знаю реализации классов для IApiClient и IUriDispenser, как это партия длл третий так, как я могу зарегистрировать его

Единство должно знать, какую реализацию использовать при разрешении интерфейса. Так почему-то вам нужно сказать Unity, какую реализацию использовать. Там отличный ответ от Mark Seemann в вопросе ниже:

Unity IoC for resolving assemblies dynamically

Она сканирует сборку для реализации своего интерфейса, а затем регистрирует их/его.

В качестве альтернативы вы можете использовать registration by convention, что позволяет сделать несколько регистраций сразу:

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(), 
    WithMapping.MatchingInterface, 
    WithName.Default, 
    WithLifetime.ContainerControlled); 

Обратите внимание, что это будет регистрировать все реализации, в том числе свои собственные. Если вы просто хотите реализаций сторонних вы должны быть в состоянии сделать что-то сделать так:

// Get the assemblies where IApiClient exists. 
IEnumerable<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies() 
    .Where(x => x.GetTypes().Contains(typeof (IApiClient))); 

// Register all implementations based on convention. 
container.RegisterTypes(AllClasses.FromAssemblies(assemblies), 
    WithMappings.FromMatchingInterface, 
    WithName.Default, 
    WithLifetime.ContainerControlled); // Maybe another lifetime manager? 

Update 2:

Убедитесь, что контроллер имеет открытый конструктор без параметров.

Ошибка выше, может иметь много причин, большинство из них покрыты в этих вопросах:

Unable to inject DBContext into my Web API 2 Controller with Unity

Make sure that the controller has a parameterless public constructor error

error: Make sure that the controller has a parameterless public constructor webapi

В основном это единство говорит вам, что вы» пытаюсь решить что-то, что вы не зарегистрировали. Или что вы еще не зарегистрировали DependencyResolver.

+0

@ Хима - Я обновил свой ответ. – smoksnes

+0

Спасибо .. Я сделал все изменения и применил решение 1 для проблемы 1..but, я получаю 500 ошибок внутреннего сервера – Hima

+0

@Hima - Не могли бы вы поделиться полученной вами ошибкой? – smoksnes