3

我正在向 Nancy 模块发送一些简单的用户详细信息。我正在利用 Nancy 的模型绑定功能从请求中获取用户详细信息并将它们传递给我的UserService.Add(...)方法,如下所示:

南希模块

Post["/add"] = parameters =>
{
    var user = this.Bind<UserDetails>();
    UserService.Add(user);
    return HttpStatusCode.OK;
};

用户详细信息类

public class UserDetails
{
    public string UserName { get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
}

用户服务

public static void Add(UserDetails user)
{
    //Add the user     
}

这在 Nancy 模块中有效并使得语法更简洁。然而,这意味着我不得不创建一个数据传输 (DTO) 类,只是为了收集请求有效负载。

是否有可能完全避免这个中间类?除了将类绑定到有效负载之外,是否可以绑定方法参数?

这将给出可能看起来像这样的代码:

南希模块

Post["/add"] = parameters =>
{
    this.BindAndCall<UserService>("Add");
    return HttpStatusCode.OK;
};

用户服务

public static void Add(string  firstName, string  lastName, string email, string userName, string password)
{
    //Add the user     
}
4

2 回答 2

3

您始终可以创建一些扩展方法或自定义绑定器,但随后您将服务的内部实现与有效负载参数的确切命名耦合,这不好,因为稍后当您的服务更改时,您需要更改有效载荷或跳槽箍。DTO 没有任何问题,创建它不需要任何成本。

于 2013-04-24T12:19:39.387 回答
3

ParameterBag - DTO 扩散的部分解决方案

在我看来,DTO 很痛苦,因为它们往往会扩散到影子域中。当您决定重新组织服务层时,这会让人头疼。

那么,为什么不直接使用dynamic类型而忘记 DTO 和强类型路由参数呢?动态值非常方便,但它们有自己的问题,主要是你不能将它们传递给扩展方法。所以更容易正确地呈现路线参数,因此模型绑定,因此 DTO 和因此意大利面条和愚蠢的帽子。

所以这里有一个部分解决方案依赖于 Nancy 的Model Binding。它显着减少了路由级别的仪式,并有助于遏制恼人的 DTO 扩散。

南希基本模块

public class _BaseModule : NancyModule
{
    public class ParameterBag
    {
        // All the params used across all routes, GET and POST
        public string UserName { get { return this.Value; } }
        public string UserIds { get; set; }
        public string UserId { get; set; }
        public string Value { get; set; }
        public int Skip { get; set; }
        public int Take { get; set; }
    }

    public ParameterBag Params;

    public _BaseModule(): this(""){}
    public _BaseModule(string modulePath): base(modulePath)
    {
        Before += ctx =>
        {
            this.Params = this.Bind<ParameterBag>();
            return null;
        };
    }
}

该类ParameterBag包含我有兴趣跨所有路由绑定的所有参数。由于 Nancy 只有在有效负载中找到匹配字段时才会填充属性,因此您可以根据需要向此类添加任意数量的属性,而无需关心它们是否会被给定路由使用。

注意绑定是如何在Before钩子中发生的。这意味着每个路由(从 派生的_BaseModule)都会自动将任何匹配的参数值绑定到通用ParameterBag类属性。不需要特定的路由级干预。

这样做的效果是为路由处理程序提供了一个可以使用的强类型参数值。

南希模块

public class UserModule : _BaseModule
{
    public UserModule()
    {
        // handlers go here
    }
}

路由处理程序示例

Get["/user/{userid}/username/available"] = _ =>
{
    return Response.AsJson(new 
        { 
            // the username is a hidden value
            // the userid comes from the url
            value = Params.UserName,
            valid = UserService.UserNameAvailable(Params.UserName, Params.UserId)
        }
    );
};

示例用法

下面的示例依赖于jqBootstrapValidation。它展示了 Binding 技巧如何适用于 URL 上提供的参数数据,作为 ajax 有效负载的一部分提供(请参阅 value 属性)。

<input 
    type="text" 
    id="username" 
    name="username" 
    placeholder="User Name" 
    data-validation-ajax-ajax="/user/@user.id/username/available" 
    data-validation-ajax-message="This name has already been taken" 
    value="@user.UserName" 
    required>
于 2013-04-24T14:13:34.047 回答