【问题标题】:Can automapper generate url's?automapper可以生成url吗?
【发布时间】:2011-06-21 09:31:16
【问题描述】:

我希望自动映射器为视图模型生成 URL。例如,这是我的数据对象:

public class User
{
  public int Id { get; set; }
  public int Name { get; set; }
}

视图模型如下所示:

public class UserListItem
{
  public string Name { get; set; }
  public string EditUrl { get; set; }
}

我希望使用为应用程序定义的路由生成EditUrl 属性。

类似这样的:

listIten.EditUrl = Url.Action("Edit", "UserController", new { id = user.Id });

似乎没有办法让 AutoMapper 做到这一点。没有 RequestContext、UrlHelper 或任何可用于映射表达式的东西,而且在调用 Mapper.Map 时我还没有找到任何传递上下文的方法。

我错过了什么吗?还是一开始就想这样做是个坏主意?

更新:附加背景

我正在研究为 MVC 视图生成 URL 的替代方法,目的是使 ASP.NET MVC 应用程序维护尽可能简单。在映射视图模型时生成 URL 是替代方法之一。很容易测试和清理视图。在某些情况下,它还将促进视图的可重用性。在尝试这个想法时,我遇到了 AutoMapper 无法接受 Map 操作的任何(动态)上下文的砖墙。

【问题讨论】:

  • @paolo 不,这不是一个重复的问题。我不是在寻求一种方法来获取视图模型中的请求上下文。不过,这可能是解决方案的开始。

标签: c# asp.net-mvc automapper


【解决方案1】:

我认为这不是 AutoMapper 的工作。

路由是特定于 ASP.NET 的,AutoMapper 真的只适用于对象映射。它没有 HTTP 上下文的可见性(也不应该),因此无法完成。

如果你想在多个地方“重用”这个逻辑,为什么不创建一个强类型的 HTML 助手呢?

public static MvcHtmlString EditUserLinkForModel<UserListItem>(this HtmlHelper<UserListItem> htmlHelper)
{
   var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
   return urlHelper.Action("Edit", 
                           "UserController", 
                           new { id = htmlHelper.ViewData.Model.UserId });
}

查看:

@Html.EditUserLinkForModel()

尽管这样可能有点矫枉过正。这是一个1班轮! :)

【讨论】:

  • 我很想听听您关于为什么 AutoMapper 不能做到这一点的论点。我的意思是,应用 HtmlEncode 也是 ASP.NET 特定的,但这是许多人使用 AutoMapper 所做的事情。 AutoMapper 是否不够灵活,无法让我为实体生成 url?毕竟生成一个 url 无非就是将几个属性值映射成一个字符串,这才是 AutoMapper 真正擅长的。
  • @Marnix - 实际上,它不仅仅是“将几个属性值映射到一个字符串”。它需要考虑路由表,该路由表仅对 http 上下文可见。如果它只是映射到一个字符串 - 你可以使用opt =&gt; opt.UseValue("somestring")。我从未见过在自动映射器中使用 HtmlEncode。但同样,这并不依赖于 HTTP 上下文。
  • 但又一次 - 我很困惑,你为什么想要自动映射器这样做?为什么在视图或助手中生成 URL 如此困难?
  • @RPM1984 我希望 AutoMapper 这样做以获得更清晰的代码。我不想创建一堆 HTML 辅助方法,我发现它很快就会变得难以管理。用 AutoMapper 实现这个对我来说似乎是一个非常干净的解决方案。至于在AutoMapper中使用HtmlEncode,这是MVC 2 In Action提倡的。
  • 接受您的回答,因为我认为您是对的。除了将数据映射和格式化到视图模型之外,Automapper 不应(ab)用于任何其他用途。
【解决方案2】:

虽然这种方法会导致许多可测试性问题,但可以做你想做的事……利用 HttpContext.Current.Request.RequestContext。

Mapper.CreateMap<Sample1, Sample2>().ForMember(
                destination => destination.Url, options => options.MapFrom(source => new UrlHelper(HttpContext.Current.Request.RequestContext).Content(source.Url)));

这会使测试变得困难,但您可以通过注入一个提供 UrlHelper 的类来解决这个问题。然后,如果可以模拟 URL 帮助程序,那么您的测试问题就会得到缓解,或者至少可以消除对 HttpContext 的依赖。

【讨论】:

    【解决方案3】:

    只是想我会分享我在这个主题上的发现......我已经使用自定义 TypeConverter (AutoMapper 3.1.1) 解决了以下问题:

    public abstract class ObjectToUrlConverter<Source> : ITypeConverter<Source, string>
    {
        public string Convert(ResolutionContext context)
        {
            UrlHelper Url = (UrlHelper)context.Options.Items["Url"];
    
            string result = null;
    
            if (context.SourceValue != null)
            {
                result = Url.Link(GetRouteName(), GetControllerName(), GetIdentifier((Source)context.SourceValue));
            }
    
            return result;
        }
    
        public abstract object GetIdentifier(Source sourceObject);
    
        public abstract string GetRouteName();
    
        public abstract string GetControllerName();
    }
    
    public class SomeEntityToUrlConverter : ObjectToUrlConverter<SomeEntity>
    {
        public override object GetIdentifier(SomeEntity sourceObject)
        {
            return sourceObject.Id;
        }
    
        public override string GetRouteName()
        {
            return "someRouteName";
        }
    
        public override string GetControllerName()
        {
            return "someControllerName";
        }
    }
    

    您可以将 ObjectToUrlConverter 子类化为您希望转换为 URL 的任何对象。 接下来,为您希望转换为 URL 的每个对象创建地图:

    Mapper.CreateMap<SomeEntity, string>().ConvertUsing<SomeEntityToUrlConverter>();
    

    最后,映射如下。 Url 是 UrlHelper 的实例。

    Mapper.Map<SourceObject[], DestinationObject[]>(items, opts => opts.Items.Add("Url", Url));
    

    现在可以将 SourceObject 中 SomeEntity 类型的任何属性正确转换为目标字符串属性,如 URL。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-10
      • 2021-05-30
      • 1970-01-01
      • 2014-05-24
      相关资源
      最近更新 更多