请在下面找到我的代码。 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方法来实现这个目标,还是我试图实现不可能?
答案 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实现每个接口。