我正在使用ServiceStack开发一个(希望)RESTful API。
我注意到我的大部分服务看起来都是一样的,例如,GET方法会看起来像这样 :
try
{
Validate();
GetData();
return Response();
}
catch (Exception)
{
//TODO: Log the exception
throw; //rethrow
}
假设我有20个资源,20个请求DTO,所以我或多或少地获得了大约20个相同模板的服务......
我试图创建一个通用或抽象的服务,所以我可以创建只实现相关行为的继承服务,但是我被卡住了,因为请求DTO不是序列化所需的。
有什么办法吗?
修改
我尝试做的一个例子:
public abstract class MyService<TResponse,TRequest> : Service
{
protected abstract TResponse InnerGet();
protected abstract void InnerDelete();
public TResponse Get(TRequest request)
{
//General Code Here.
TResponse response = InnerGet();
//General Code Here.
return response;
}
public void Delete(TRequest request)
{
//General Code Here.
InnerDelete();
//General Code Here.
}
}
public class AccountService : MyService<Accounts, Account>
{
protected override Accounts InnerGet()
{
throw new NotImplementedException();//Get the data from BL
}
protected override void InnerDelete()
{
throw new NotImplementedException();
}
}
答案 0 :(得分:4)
为了在New API中执行此操作,我们引入了IServiceRunner的概念,该服务将服务的执行与其实现分离。
要添加自己的Service Hook,您只需要从其默认实现中覆盖AppHost中的默认Service Runner:
public virtual IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new ServiceRunner<TRequest>(this, actionContext); //Cached per Service Action
}
用你自己的:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new MyServiceRunner<TRequest>(this, actionContext); //Cached per Service Action
}
MyServiceRunner只是一个实现您感兴趣的自定义钩子的自定义类,例如:
public class MyServiceRunner<T> : ServiceRunner<T> {
public override void OnBeforeExecute(IRequestContext requestContext, TRequest request) {
// Called just before any Action is executed
}
public override object OnAfterExecute(IRequestContext requestContext, object response) {
// Called just after any Action is executed, you can modify the response returned here as well
}
public override object HandleException(IRequestContext requestContext, TRequest request, Exception ex) {
// Called whenever an exception is thrown in your Services Action
}
}
另外,对于更细粒度的错误处理选项,请查看Error Handling wiki page。
答案 1 :(得分:0)
我的解决方案是添加一个附加层,我可以在其中处理每个实体的逻辑:
基本逻辑示例:
class User(AbstractUser):
... # fields
objects = MedicalUserManager()
class MedicalUserManager(models.UserManager):
def create_user(self, username, email=None, password=None, **extra_fields):
# pop all fields you want to use for `Doctor` or `Patient` from `extra_fields`
doctor_pin = extra_fields.pop('doctor_pin', None)
pid = extra_fields.pop('pid', None)
user = super().create_user(username, email, password, **extra_fields)
if doctor_pin:
doctor = Doctor.objects.create(user=user, upin=doctor_pin)
user.is_doctor = True # not needed if `is_doctor` is in `extra_fields` because it would have been saved when creating the `User`
user.save()
elif pid:
patient = Patient.objects.create(user=user, pid=pid)
user.is_patient = True
user.save()
return user
然后我们可以使用钩子:
public interface IEntity
{
long Id { get; set; }
}
public interface IReadOnlyLogic<Entity> where Entity : class, IEntity
{
List<Entity> GetAll();
Entity GetById(long Id);
}
public abstract class ReadOnlyLogic<Entity> : IReadOnlyLogic<Entity> where Entity : class, IEntity, new()
{
public IDbConnection Db { get; set; }
#region HOOKS
protected SqlExpression<Entity> OnGetList(SqlExpression<Entity> query) { return query; }
protected SqlExpression<Entity> OnGetSingle(SqlExpression<Entity> query) { return OnGetList(query); }
#endregion
public List<Entity> GetAll()
{
var query = OnGetList(Db.From<Entity>());
return Db.Select(query);
}
public Entity GetById(long id)
{
var query = OnGetSingle(Db.From<Entity>())
.Where(e => e.Id == id);
var entity = Db.Single(query);
return entity;
}
}
最后,我们的服务仅调用我们的逻辑:
public interface IHello : IReadOnlyLogic<Hello> { }
public class HelloLogic : ReadOnlyLogic<Hello>, IHello
{
protected override SqlExpression<Hello> OnGetList(SqlExpression<Hello> query)
{
return query.Where(h => h.Name == "Something");
}
}