简体   繁体   English

常规WCF服务

[英]Generic WCF Service

I know there are a lot of questions with and without answer about this topic but none seem to match exactly with the issue that I have. 我知道关于此主题有很多问题,有没有答案,但似乎没有一个与我所遇到的问题完全匹配。

I'm trying to write manager services for my project's entities. 我正在尝试为我的项目实体编写经理服务。 For the main, big and important ones I have already done it but the business contains a lot of descriptors (entities with only ID and Name that are used by other entities) that I'd like to be able to manage as services too. 对于主要,重要的重要对象,我已经完成了,但是业务包含许多描述符(其他实体仅使用ID和Name的实体),我也希望将其作为服务来管理。

One solution would be to have a specific manager for each of them but that would definitely break maintainability due to the number of descriptors. 一种解决方案是为每个应用程序指定一个特定的管理器,但是由于描述符的数量,肯定会破坏可维护性。 So I wrote 2 interfaces as follows 所以我写了两个接口如下

public interface IIdentifiableEntity
{
    string EntityId { get; set; }
}

public interface IDescriptorEntity: IIdentifiableEntity
{
    string EntityDesc { get; set; }
}

This is due to my main entities implement IIdentifiableEntity and my descriptors implement IDescriptorEntity 这是由于我的主要实体实现了IIdentifiableEntity,而我的描述符实现了IDescriptorEntity

Here is an example of one of my descriptor entities: 这是我的描述符实体之一的示例:

public class JobCode: IDescriptorEntity
{
    [DataMember]
    public string JobCodeID { get; set; }
    [DataMember]
    public string JobCodeDesc { get; set; }

    public string EntityId
    {
        get
        {
            return JobCodeID;
        }

        set
        {
            JobCodeID = value;
        }
    }

    public string EntityDesc
    {
        get
        {
            return JobCodeDesc;
        }

        set
        {
            JobCodeDesc = value;
        }
    }
}

Then I wrote my service contract as follows: 然后我写了我的服务合同,内容如下:

public interface IDescriptorService : IServiceContract
{
    [OperationContract]
    [FaultContract(typeof(NotFoundException))]
    T Get<T>(string id) where T : class, IDescriptorEntity, new();

    [OperationContract]
    T[] GetAll<T>() where T : class, IDescriptorEntity, new();

    [OperationContract]
    [TransactionFlow(TransactionFlowOption.Allowed)]
    T Add<T>(T descriptor) where T : class, IDescriptorEntity, new();

    [OperationContract]
    [TransactionFlow(TransactionFlowOption.Allowed)]
    T Update<T>(T descriptor) where T : class, IDescriptorEntity, new();

    [OperationContract]
    [TransactionFlow(TransactionFlowOption.Allowed)]
    void Delete<T>(string id) where T : class, IDescriptorEntity, new();
}

And my manager (the service itself) as follows: 而我的经理(服务本身)如下:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
    ConcurrencyMode = ConcurrencyMode.Multiple,
    ReleaseServiceInstanceOnTransactionComplete = false)]
[Export(typeof(IDescriptorService))]
public class DescriptorManager : ManagerBase, IDescriptorService
{
    public DescriptorManager()
    {
        ObjectBase.Container.SatisfyImportsOnce(this);
    }

    #region No MEF Discovery constructors
    public DescriptorManager(IDataRepositoryFactory dataRepositoryFactory)
    {
        _DataRepositoryFactory = dataRepositoryFactory;
    }
    #endregion

    [Import]
    IDataRepositoryFactory _DataRepositoryFactory;

    [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
    public TEntityType Get<TEntityType>(string id) where TEntityType : class, IDescriptorEntity, new() => ExecuteFaultHandledOperation(() =>
    {
        IDataRepository<TEntityType> repository = _DataRepositoryFactory.GetDataRepositoryOf<TEntityType>();

        TEntityType entity = repository.Get(id);

        if (entity == null)
        {
            NotFoundException ex
                = new NotFoundException(string.Format("{0} with ID of {1} is not in the database", typeof(TEntityType).Name, id));

            throw new FaultException<NotFoundException>(ex, ex.Message);
        }

        return entity;
    });

    [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
    public TEntityType[] GetAll<TEntityType>() where TEntityType : class, IDescriptorEntity, new() => ExecuteFaultHandledOperation(() =>
    {
        IDataRepository<TEntityType> repository = _DataRepositoryFactory.GetDataRepositoryOf<TEntityType>();

        IEnumerable<TEntityType> entities = repository.Get();

        return entities.ToArray();
    });

    [OperationBehavior(TransactionScopeRequired = true)]
    [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
    public TEntityType Update<TEntityType>(TEntityType entity) where TEntityType : class, IDescriptorEntity, new() => ExecuteFaultHandledOperation(() =>
    {
        IDataRepository<TEntityType> repository = _DataRepositoryFactory.GetDataRepositoryOf<TEntityType>();

        TEntityType updatedEntity = repository.Update(entity);

        return updatedEntity;
    });

    [OperationBehavior(TransactionScopeRequired = true)]
    [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
    public TEntityType Add<TEntityType>(TEntityType entity) where TEntityType : class, IDescriptorEntity, new() => ExecuteFaultHandledOperation(() =>
    {
        IDataRepository<TEntityType> repository = _DataRepositoryFactory.GetDataRepositoryOf<TEntityType>();

        TEntityType updatedEntity = repository.Add(entity);

        return updatedEntity;
    });

    [OperationBehavior(TransactionScopeRequired = true)]
    [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
    public void Delete<TEntityType>(string id) where TEntityType : class, IDescriptorEntity, new() => ExecuteFaultHandledOperation(() =>
    {
        IDataRepository<TEntityType> repository = _DataRepositoryFactory.GetDataRepositoryOf<TEntityType>();

        repository.Remove(id);
    });
}

And the hosting app as a console app as follows: 并将托管应用程序作为控制台应用程序,如下所示:

class Program
{
    static void Main(string[] args)
    {
        ObjectBase.Container = MEFLoader.Init();

        Console.WriteLine("Starting up services...");
        Console.WriteLine("");

        SM.ServiceHost hostDescriptorManager = new SM.ServiceHost(typeof(DescriptorManager));
        SM.ServiceHost hostPositionManager = new SM.ServiceHost(typeof(PositionManager));
        SM.ServiceHost hostEmployeeManager = new SM.ServiceHost(typeof(EmployeeManager));

        StartService(hostDescriptorManager, "DescriptorManager");
        StartService(hostPositionManager, "PositionManager");
        StartService(hostEmployeeManager, "EmployeeManager");

        Console.WriteLine("");
        Console.WriteLine("Press [Enter] to exit.");
        Console.ReadLine();

        StopService(hostDescriptorManager, "DescriptorManager");
        StopService(hostPositionManager, "PositionManager");
        StopService(hostEmployeeManager, "EmployeeManager");
    }

    static void StartService(SM.ServiceHost host, string serviceDescription)
    {
        host.Open();
        Console.WriteLine("Service {0} started", serviceDescription);

        foreach (var endpoint in host.Description.Endpoints)
        {
            Console.WriteLine("Listening on endpoints:");
            Console.WriteLine("Adress: {0}", endpoint.Address.Uri);
            Console.WriteLine("Binding: {0}", endpoint.Binding.Name);
            Console.WriteLine("Contract: {0}", endpoint.Contract.Name);
        }

        Console.WriteLine();
    }

    static void StopService(SM.ServiceHost host, string serviceDescription)
    {
        host.Close();
        Console.WriteLine("Service {0} stopped.", serviceDescription);
    }
}

I'd also like to have some composition and DI (I'm using MEF to compose the whole app) and thus I have my entities (descriptors included) in a separate assembly that I load. 我还希望有一些组成和DI(我正在使用MEF组成整个应用程序),因此我将实体(包括描述符)放在加载的单独程序集中。 Therefore having "KnownType" directly hard coded in my classes and interfaces would just not work. 因此,直接在我的类和接口中硬编码“ KnownType”将无法正常工作。

So I tried following this example from MSDN and write the known types in a config file (that I can change later and so maintain my composition). 因此,我尝试按照MSDN上的示例进行操作,并将已知类型写入配置文件(以后可以更改以保持其组成)。 Following a part of the config in which I'm trying to add the JobCode descriptor as KnownType. 在配置的一部分之后,我尝试将JobCode描述符添加为KnownType。

<system.runtime.serialization>
<dataContractSerializer>
  <declaredTypes>
    <add type="Core.Common.Contracts.IDescriptorEntity,Core.Common.Contracts">
      <knownType type="XXXX.Business.Entities.JobCode,XXXX.Business.Entities"/>
    </add>
  </declaredTypes>
</dataContractSerializer>

Yet when I try to run the host I get again the "Open Generics" error at the first method of the IDescriptorService interface. 但是,当我尝试运行主机时,在IDescriptorService接口的第一种方法中再次出现“ Open Generics”错误。

What am I doing wrong? 我究竟做错了什么?

One solution would be to have a specific manager for each of them but that would definitely break maintainability due to the number of descriptors 一种解决方案是为每个应用程序都有一个特定的管理器,但是由于描述符的数量,肯定会破坏可维护性

And really that's the correct solution. 确实,这是正确的解决方案。 A WCF Service has to have a contract that tells the client the shape of the entity to expect. WCF服务必须有一个合同,告知客户期望的实体形状。 You write a T4 Template to generate all the Service Contracts and Service Classes. 您编写一个T4模板以生成所有服务合同和服务类别。

Stepping back, having web services for CRUD on your entities isn't a really good practice. 退一步,在您的实体上使用CRUD的Web服务并不是一个好习惯。 You're generally better off accessing the entity model directly, rather than across web services. 通常最好直接访问实体模型,而不是跨Web服务访问。 It's obviously much simpler, and performs much better. 它显然要简单得多,并且性能要好得多。 And accessing your entities across web services doesn't really accomplish anything useful. 跨Web服务访问实体并不能真正完成任何有用的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM