DI в сервисном контракте WCF - PullRequest
2 голосов
/ 22 ноября 2011

Пожалуйста, найдите ниже мой код. Класс Employee реализует интерфейс IEmployee.

    namespace MiddleWare.ServiceContracts

    {
        [ServiceContract(Namespace = "http://mywebsite.com/MyProject")]

        public interface IMiscellaneous
        {
           [OperationContract]
            [ServiceKnownType(typeof(MiddleWare.Classes.Employee))]
            IEnumerable<IEmployee> Search_Employee
            (string SearchText);

    }


    namespace MiddleWare.ServiceClasses
    {
       public class Miscellaneous : IMiscellaneous
        {
           public IEnumerable<IEmployee> Search_Employee
            (string SearchText)
            {
               List<IEmployee> emp = new List<IEmployee>();

               IEmployee TempObject = (IEmployee)Activator.CreateInstance(typeof(IEmployee));  
               TempObject.EmployeeId = "12345678";

               emp.Add(TempObject);
              return emp;
           }
       }
    }

Как видно, приведенный выше код компилируется, но не работает, потому что экземпляр интерфейса не может быть создан. Как я могу получить DI (Dependency Injection) здесь ... Если я напишу ..

IEmployee TempObject = (IEmployee)Activator.CreateInstance(typeof(Employee));

Тогда этот класс будет зависеть не только от интерфейса, но и от класса ... при условии, что в один прекрасный день класс Employee станет Employee2.В двух местах будут изменения кода .. 1) [ServiceKnownType(typeof(MiddleWare.Classes.Employee2))]

2) IEmployee TempObject = (IEmployee)Activator.CreateInstance(typeof(Employee2));

Я хочу этого избежать. Можем ли мы что-то сделать при реализации IOperationBehavior, или есть Ninject способ достижения этого или я пытаюсь достичь невозможного?

Ответы [ 4 ]

2 голосов
/ 22 ноября 2011

Подумайте об изменении дизайна. Используйте фабричный шаблон для создания экземпляра вашего сотрудника.

public EmployeeFactory : IEmployeeFactory 
{
  public IEmployee CreateEmployee() 
  {
    return new Employee();
  }
}

И добавьте зависимость от Factory из вашего промежуточного ПО, поэтому создание нового IEmployee становится:

public class Miscellaneous : IMiscellaneous 
{ 
    private readonly IEmployeeFasctory _employeeFactory;

    public class Miscellaneous(IEmployeeFactory employeeFactory)
    {
        _employeeFactory = employeeFactory;
    }

    public IEnumerable Search_Employee (string searchText) 
    { 
       List employees = new List();
       IEmployee employee = _employeeFactory.CreateEmployee();  
       employee.EmployeeId = "12345678";
       employees.Add(TempObject);
       return employees;
}

И тогда вы можете добавить свой EmployeeFactory в Разное.И если Сотрудник однажды станет устаревшим, и Сотрудник2 придет, просто смени фабрику!

1 голос
/ 23 ноября 2011

Провел обсуждение внутри команды.

1) Реализация на основе конструктора неудобна. Служба будет размещаться и использоваться IIS в качестве веб-ссылки. Невозможно попросить клиентские системы предоставить FactoryImplementatedObjects в вызове класса Разное.

2) Фабрики, основанные на сущностях, также не совсем точны. Если в моем проекте, скажем, есть 20 конкретных сущностей, таких как «Сотрудник», «Материал», «Проект», «Расположение», «Заказ»), то мне нужно иметь 20 фабрик. Также у класса «Разное» будет несколько пользовательских конструкторов для поддержки определенных вызовов контракта.

Я подготовил систему, которая работает, и DI достигнут на отличном уровне, но я чувствую, что я обманываю. Упс .. Не чувствую себя правильно в глубине души .. но нельзя опровергнуть, что я ошибался .. Пожалуйста, проверьте и позвольте мне знаю ваши комментарии.

Теперь у меня есть интерфейс IEntity, который является базой для всех других сущностей.

namespace BusinessModel.Interfaces
{
    public interface IEntity
    {
        string EntityDescription { get; set; }
    }
}

Следовательно, все будут реализовывать это.

namespace BusinessModel.Interfaces
{
    public interface IEmployee : IEntity
    {
        string EmployeeId { get; set ; } 
    }
}

namespace BusinessModel.Interfaces
{
    public interface IProject : IEntity
    {
        string ProjectId { get; set; }
    }
}

и т. Д. (Интерфейс, реализующий интерфейс ... абсолютно нелепый, читерский, но работающий)

Далее объявляется, что тип Enum имеет список всех сущностей ...

namespace MiddleWare.Common
{
    internal enum BusinessModel
    {
        IEmployee,
        IProject
    }
}

Создается класс DI Helper, который отныне будет рассматриваться как часть бизнес-модели, и любые изменения в нем (Внедрение, Именование ...) будут восприниматься как бизнес-сдвиг. Так что если класс DIHelper должен стать DIHelper2, то это как БОЛЬШОЙ (можно ли этого избежать ??)

namespace MiddleWare.Common
{
    internal sealed class DIHelper
    {
        internal static IEntity GetRequiredIEntityBasedObject(BusinessModel BusinessModelObject)
        {
            switch (BusinessModelObject)
            {
                case BusinessModel.IEmployee:
                    return new Employee();
            }

            return null;
        }
    }
}

Функция самообъяснительная ...

Итак, наконец, контракт и реализация ...

namespace MiddleWare.ServiceContracts
{
[ServiceContract(Namespace = "http://mywebsite.com/MyProject")] 
public interface IMiscellaneous
    {
    [OperationContract]
    [ServiceKnownType(typeof(MiddleWare.Classes.Employee))]
    IEnumerable<IEmployee> Search_Employee
        (string SearchText);
    }
}

namespace MiddleWare.ServiceClasses
{
    public class Miscellaneous : IMiscellaneous
    {
        public IEnumerable<IEmployee> Search_Employee
            (string SearchText)
        {
            List<IEmployee> IEmployeeList = new List<IEmployee>();

            IEmployee TempObject = (IEmployee)DIHelper.GetRequiredIEntityBasedObject(MiddleWare.Common.BusinessModel.IEmployee);
            TempObject.EmployeeId = "12345678";

            IEmployeeList.Add(TempObject);
            return IEmployeeList;
        }
    }
}

Что ты скажешь ?? Моя команда счастлива, хотя:)

1 голос
/ 22 ноября 2011

Как указывает rich.okelly в другом ответе, IEmployeeFactory следует использовать для создания экземпляров интерфейса IEmployee, , поскольку IEmployee не Служба, а сущность .

Интерфейс IEmployeeFactory, с другой стороны, является Сервисом, поэтому его следует внедрить в класс сервиса с помощью Конструкторское внедрение . Вот описание включения Constructor Injection в WCF .

0 голосов
/ 23 ноября 2011

Исходя из ваших обновленных требований, в этом вопросе нет ничего, касающегося DI ...

Итак, чтобы создать тип, основанный на известных сервисных типах контракта на обслуживание, вы можете использовать:

public class EntityLoader<TServiceContract>
    {
        private static readonly HashSet<Type> ServiceKnownTypes = new HashSet<Type>();
        static EntityLoader()
        {
            var attributes = typeof(TServiceContract).GetMethods().SelectMany(m => m.GetCustomAttributes(typeof(ServiceKnownTypeAttribute), true)).Cast<ServiceKnownTypeAttribute>();
            foreach (var attribute in attributes)
            {
                ServiceKnownTypes.Add(attribute.Type);
            }
        }

        public TEntity CreateEntity<TEntity>()
        {
            var runtimeType = ServiceKnownTypes.Single(t => typeof(TEntity).IsAssignableFrom(t));
            return (TEntity)Activator.CreateInstance(runtimeType);
        }
    }

Что тогда можно использовать следующим образом:

    [ServiceContract(Namespace = "http://mywebsite.com/MyProject")]
    public interface IMiscellaneous
    {
        [OperationContract]
        [ServiceKnownType(typeof(Employee))]
        IEnumerable<IEmployee> SearchEmployee(string SearchText);
    }

    public class Miscellaneous : IMiscellaneous
    {
        private readonly EntityLoader<IMiscellaneous> _entityLoader = new EntityLoader<IMiscellaneous>();
        public IEnumerable<IEmployee> SearchEmployee(string SearchText)
        {
            List<IEmployee> employees = new List<IEmployee>();

            IEmployee employee = _entityLoader.CreateEntity<IEmployee>();
            employee.EmployeeId = "12345678";

            employees.Add(employee);
            return employees;
        }
    }

Очевидно, что в приведенном выше коде предполагается, что ALL ваших сервисных сущностей будет содержать общедоступные безпараметрические конструкторы и что будут толькоодин ServiceKnownType, который реализует каждый интерфейс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...