在一个asp.net-mvc网站上,处理可编辑和只读视图有好的模式吗?

4
我有一个asp.net-mvc网站,直到现在都没有权限限制,对所有人开放。许多页面都是详细的表单,包括文本框、下拉选择框等。
现在我需要更改这个网站,使得许多现有页面具有“权限”,只有特定的人才能编辑,其他人只能看到只读页面。我正在尝试弄清楚是否应该:
  1. Create a seperate view for everyone one of my existing views with forms that is just read only html on a page and redirect based on entitlements on the server side, something like

    public ActionResult OrderView()
    {
         var isEntitled = Model.IsEntitled()
         if (isEntitled)
         { 
              return("OrderEditableView", GetViewModel()); 
         }
         else 
         {
             return("OrderReadOnlyView", GetViewModel());  
         }
    

    }

或者

  1. 重复使用同一个视图,并在屏幕上禁用或隐藏“保存”按钮。

在我的视图中有:

     <% if (Model.IsEntitled) { %>
           <button id="saveButton">Save Changes</button>
     <% } %>

第二个选项实现起来会更快,但是看起来有些奇怪,因为它看起来像你可以编辑所有字段,但只是没有看到(或看到了禁用的)保存按钮。
第一个选项似乎更清晰,但我必须去为每个屏幕创建一个新视图,这似乎需要很多工作(目前有超过100个视图)。
这似乎是一个常见的情况,所以我想知道处理这种情况的最佳实践。显然,我正在寻找解决方案,但如果我从头开始,我也会对被认为是最佳实践或推荐解决方案的模式感兴趣。

听起来你需要建立一个服务器会话类,在其中可以放置像MyWeb.Session.isEntitled这样的东西。 - Ross Bush
@Irb - 我没有问题计算和确定某人是否有资格。根据我的问题,我更关注如何管理视图。 - leora
您可以根据可编辑的要求创建一个部分视图。 - Ross Bush
@Irb - 难道那不是我上面列出的第一个选项吗? - leora
有很多模式可以做你想做的事情。但是:你是否使用EditorFor助手来呈现所有要转换为被动控件的输入控件?非管理用户看到停用的输入框是否可以接受(或者您需要让他们看到简单文本)?调整“微调”或使用自定义助手太麻烦吗,而您希望改变其行为?您是否同意从JS库(如Angular)添加一些功能? - Dave Alperovich
4个回答

6
我会为两者都创建单独的部分/完整视图。
原因是: 易于更改和维护; 验证代码仅在可编辑部分中; 关注点明确的清晰分离; 代码更加简洁; 可以通过将相似的代码抽象/分离到可重用的部分视图中来重用某些代码; 易于控制访问。
此外,在现实世界中,我们需要平衡预算、时间和精力,因此根据情况可能会使用这些内容的混合。

3
一个选项是在视图中进行切换。
<% if (Model.IsEntitled) 
{ 
    Html.Partial("OrderEditablePartialView", Model)
}
else 
{
    Html.Partial("OrderReadOnlyPartialView", Model)
}
%>

另一种选择是创建自定义的Html助手来呈现元素以进行编辑或只读,这将为您提供一些灵活性,以便您可以处理每个元素的方式。
粗略示例:
public static MvcHtmlString FormTextBox(this HtmlHelper helper, string name, string text, bool editable)
        {
            return
                new MvcHtmlString(
                    String.Format(
                        editable
                            ? "<input type='text' id='{0}' name='{0}' value='{1}'>"
                            : "<label for='{0}'>{1}</label>",
                            name, text));
        }

将 OP 的建议从控制器移动到视图并不会有太大的改变,而 OP 说:“但我必须为每个屏幕创建一个新视图,这似乎是很多工作(目前有超过100个视图)”,这并不能解决问题。 - CodeCaster
+1 为扩展方法。这样,你只需编写一次视图,它就知道自己的属性。不过,我会使用内置的EditorFor和DisplayFor模板:public static MvcHtmlString EditOrDisplayFor( this HtmlHelper html, Expression> expression, bool isEditable) { return (isEditable) ? html.EditorFor(expression):html.DisplayFor(expression); } - Colby Cavin

3

我会选择第二个选项,使用一个视图来展示可写和只读表单。

在视觉方面,除了隐藏“保存”按钮之外,我还会实现一些东西:

  • 将输入字段设置为只读。您可以使用客户端JavaScript轻松实现此目的。

  • 更改输入字段的颜色(可能还有其他属性)以强调它们是只读的(例如,删除边框)。这可以通过样式表和表单标签中的单个附加类名轻松实现。

服务器端的授权也很简单。只需相应地注释操作即可。

它可能看起来像这样(使用Razor和jQuery进行简化):

视图:

@using (Html.BeginForm("AddressController", "SaveChanges", FormMethod.Post,
        new { @class = Model.IsEntitled ? "regular" : "readonly"}))
{
   <p>
     @Html.TextboxFor(model => model.Name)
   </p>
   <p>
     @Html.TextboxFor(model => model.Address)
   </p>
   @if (Model.IsEntitled) {
     <p>
       <button id="saveButton">Save Changes</button>
     </p>
   }
}

<script type="text/javascript">
  $( document ).ready(function() {
     $('form.readonly input').attr("readonly", true);
  });
</script>

控制器:

public class AddressController : Controller {

    [Authorize(Roles = "xyz")]
    [HttpPost]
    public ActionResult SaveChanges(Address address) {
        ...
    }
}

CSS:

.readonly input {
    border: none;
}

我认为这是一个很好的解决方案。虽然在客户端使用JavaScript可能不是最理想的方式,但它是一个很好的折衷方案,因为它避免了手动更改每个输入元素的麻烦。 - Ben Aaronson

1
最快的解决方案是使用一些JavaScript,禁用那些用户没有权限的页面上的所有输入元素。如何实现取决于您的视图和模型的结构。这样,您可以重复使用编辑视图,甚至不必编辑它们,但根据您拥有的用户类型,您可能会遇到“站点无法工作”的请求,因为您的表单看起来被禁用了。
最佳做法或建议的解决方案是使用适当的视图模型DisplayTemplates 和 EditorTemplates,但是从您的评论“为每个屏幕创建新视图似乎需要大量的工作”中我理解您对此不感兴趣。所以,我会选择前者。请确保检查[HttpPost]动作方法中的权限,因为恶意用户可以轻松地重新启用表单并提交它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接