服务合同WCF中的DI

时间:2011-11-22 11:42:31

标签: wcf service dependency-injection ninject contract

请在下面找到我的代码。 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(依赖注入)...如果我写...

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

然后这个类不仅依赖于接口而且还依赖于类...假设一个晴天Employee类成为Employee2.There会在两个地方进行代码更改。 1)[ServiceKnownType(typeof(MiddleWare.Classes.Employee2))]

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

我想避免这种情况。我们可以在实现IOperationBehavior时做些什么,还是有Ninject方法来实现这个目标,还是我试图实现不可能?

4 个答案:

答案 0 :(得分:2)

考虑设计更改 - 使用工厂模式创建员工实例。

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注入Miscellaneous。并且员工有一天会被弃用而且Employee2出现了,只需更换工厂!

答案 1 :(得分:1)

正如rich.okelly在另一个答案中指出的那样,IEmployeeFactory应该用于创建IEmployee界面since IEmployee isn't a Service, but an Entity的实例。

另一方面,IEmployeeFactory接口是一个服务,因此应使用构造函数注入将其注入服务类。 Here's a write-up of enabling Constructor Injection in WCF

答案 2 :(得分:1)

在团队内部进行了讨论。

1)基于构造函数的实现不舒服。该服务将作为Web引用进行IIS托管和使用。不要求客户端系统在其他类调用中提供FactoryImplementatedObjects。

2)基于实体的工厂也不是绝对准确。如果我在项目中碰巧说了20个特定实体,如员工,材料,项目,位置,订单,那么我需要有20个工厂。此外,杂项课程将有几个自定义构造函数,以支持特定的合同调用..

我已经准备好了一个正在运行的系统,并且DI达到了很高的水平但是我觉得我在欺骗OOPS ..心里感觉不错..但不能被驳斥是错的。请检查并让我知道你的意见。

我现在有一个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,那么这是像BIG。(这也可以避免吗?)

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;
        }
    }
}

你怎么说? 我的团队很开心:)

答案 3 :(得分:0)

根据您更新的要求,此问题中没有任何与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实现每个接口。