简体   繁体   中英

Using multiple WCF service contracts

我的项目越来越大,直到现在我只有一份服务合同,是否应该将端点拆分为多个服务合同?

Along with the essential reading that marc_s posted in the comment, there is another good reason for splitting your services.

If you have (say) a Customer service, an Order service, etc, you can then create a generic business logic layer, and have your services pass calls through to that. As your services now only relate to one specific entity, can can inject a business layer object generic to that entity. This means you can avoid a lot of boilerplate code in each service, as your common service calls, such as the CRUD calls, can be handled by the generic business logic layer.

For example, here is a simple generic business logic layer...

public class BaseServiceLogic<T> : BaseServiceLogicInterface<T> where T : class, EntityInterface {
  #region Inject

  [Inject]
  public ILog Logger { get; set; }

  [Inject]
  public BaseRepositoryInterface<T> Repository { get; set; }

  #endregion

  public virtual T GetByID(int id) {
    return Repository.GetByID(id);
  }

  public virtual IEnumerable<T> GetAll() {
    return Repository.GetAll();
  }

  public virtual int Update(int userID, T entity) {
    Logger.Debug("Updating entity (" + entity.ID + ") " + entity.Description + ", user ID " + userID);
    bool newItem = (entity.ID == 0);
    T updatedEntity = Repository.Update(entity);
    if (newItem) {
      Logger.Debug("  ID is now " + updatedEntity.ID);
    }
    return updatedEntity.ID;
  }

  public IEnumerable<ParseError> UpdateEntities(int userID, IEnumerable<T> entities) {
    List<ParseError> errors = new List<ParseError>();
    foreach (T entity in entities) {
      try {
        Update(userID, entity);
      }
      catch (Exception ex) {
        errors.Add(new ParseError {
          EntityID = entity.ID,
          Message = "Saving " + typeof(T) + ": " + ex.Message
        });
      }
    }
    return errors;
  }

  public virtual void Delete(int userID, int id) {
    string description = Repository.GetByID(id).Description;
    Logger.Debug("Deleting entity (" + id + ") " + description + ", user ID " + userID);
    Repository.Delete(id);
  }
}

The base repository would look like this...

public class BaseRepository<T> : BaseRepositoryInterface<T> where T : class, EntityInterface {
  private readonly MyEntities _ctx;
  private readonly DbSet<T> _dbSet;
  private readonly ILog _logger;

  public BaseRepository(AkivaLiebermanEntities ctx, ILog logger) {
  _ctx = ctx;
  _dbSet = _ctx.Set<T>();
  _logger = logger;
}

  public T GetByID(int id) {
  return _dbSet.FirstOrDefault(e => e.ID == id);
}

  public IEnumerable<T> GetAll() {
  return _dbSet;
}

  public T Update(T entity) {
    _logger.Debug("Update(" + entity.ID + ") - " + entity.Description);
    T existingEntity = GetByID(entity.ID);
    if (existingEntity == null) {
      return CreateNew(entity);
    }
    try {
      _ctx.Entry(existingEntity).CurrentValues.SetValues(entity);
      _ctx.SaveChanges();
    }
    catch (Exception ex) {
      _logger.Error("Exception: " + ex.MessageStack());
      throw;
    }
    return existingEntity;
  }

  private T CreateNew(T newEntity) {
    _logger.Debug("CreateNew()");
    try {
      _dbSet.Add(newEntity);
      _ctx.SaveChanges();
    }
    catch (Exception ex) {
      _logger.Error("Exception: " + ex.MessageStack());
      throw;
    }
    _logger.Debug("CreateNew() - new entity: " + newEntity.Description);
    return newEntity;
  }

  public virtual void Delete(int id) {
    T entity = _dbSet.FirstOrDefault(e => e.ID == id);
    if (entity != null) {
      _logger.Debug("Delete(" + id + ") - " + entity.Description);
      try {
        _dbSet.Remove(entity);
        _ctx.SaveChanges();
      }
      catch (Exception ex) {
        _logger.Error("Exception: " + ex.MessageStack());
        throw;
      }
    } else {
      _logger.Debug("Delete(" + id + ") - Not found");
    }
  }
}

With this, your service code could just inject an instance of the base business logic, and call the methods there, saving you from writing a business logic call for each type. For example, you could have a Customer service that would inject something like this...

[Inject]
public BaseServiceLogicInterface<Customer> CustomerServiceLogic { get; set; }

Then your service could update a customer as follows...

[OperationContract]
public void UpdateCustomer(Customer c) {
  return CustomerServiceLogic.Update(c);
}

Notice how you didn't need to write any entity-specific code here? If you wanted a Contact service, you could just create a .svc part, and have similar code to the above, again without needing a specific contact business logic class.

Even if you do need to create specific business logic classes for more entity-specific operations, you still get the basic operations for free by using the base classes.

Hope that makes sense.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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