我的项目越来越大,直到现在我只有一份服务合同,是否应该将端点拆分为多个服务合同?
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.