asp.net MVC新手。我有一个有多个字段的表。我想构建输入规则,用户必须在Field1或Field2的下拉列表中选择一个值。如果同时为Field1和Field2选择了值,或者如果Field1或Field2都没有选定值,则用户将无法发布。
我的两难困境在于决定应该记录输入逻辑或规则的位置(Controller vs View)?据我了解,最佳做法是保持Controller简单和“瘦”,所以我将输入规则放在View中使用Razor?如果是这样,怎么样?
提前感谢您的建议。
以下是模型:
public class Order
{
public int OrderID {get; set;}
public string Field1 {get; set;}
public string Field2 {get; set;}
//other properties
}
我在Controller中使用viewbags来创建下拉列表:
// GET: Order/Create
public ActionResult Create()
{
ViewBag.Field1 = new SelectList(db.Field1.OrderBy(x => x.Name), "Name", "Name");
ViewBag.Field2 = new SelectList(db.Field2.OrderBy(z => z.Clip), "Clip", "Clip");
return View();
}
查看:
<div class="form-group">
@Html.LabelFor(model => model.Field1, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.Field1, (SelectList)ViewBag.Field1, "Select one...", htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Field1, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Field2, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.Field2, (SelectList)ViewBag.Field2, "Select one...", htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Field2, "", new { @class = "text-danger" })
</div>
</div>
答案 0 :(得分:0)
您可以执行以下操作。我在代码中解释了每个项目的位置:
查看:
@*put model reference here*@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>IndexValid9</title>
</head>
<body>
@using (Html.BeginForm())
{
<table>
<tr>
<td>
@Html.DropDownListFor(m => m.SelectedA,
new SelectList(Model.TableAList, "Value", "Text"))
@Html.ValidationMessageFor(model => model.SelectedA)
</td>
</tr>
<tr>
<td>
@Html.DropDownListFor(m => m.SelectedB,
new SelectList(Model.TableAList, "Value", "Text"))
@Html.ValidationMessageFor(model => model.SelectedB)
</td>
</tr>
</table>
<input type="submit" value="submit" />
}
</body>
</html>
控制器型号
//You can put this in a model folder
public class FieldViewModel
{
public FieldViewModel()
{
TableAList = Utilites.GetTableAList();
TableBList = Utilites.GetTableBList();
}
public List<SelectListItem> TableAList { get; set; }
public List<SelectListItem> TableBList { get; set; }
public int SelectedA { get; set; }
public int SelectedB { get; set; }
}
//You can put this in its own folder
public class Utilites
{
public static List<SelectListItem> GetTableAList()
{
List<SelectListItem> list = new List<SelectListItem>();
try
{
using (BreazEntities31 entity = new BreazEntities31())
{
entity.TableAs.
OrderBy(r => r.Text).ToList().ForEach(r => list.Add(
new SelectListItem { Text = r.Text, Value = r.Value.ToString() }));
}
}
catch (Exception e)
{ }
//add <select> to first item
list.Insert(0, new SelectListItem { Text = "", Value = "" });
return list;
}
public static List<SelectListItem> GetTableBList()
{
List<SelectListItem> list = new List<SelectListItem>();
try
{
using (BreazEntities31 entity = new BreazEntities31())
{
entity.TableBs.
OrderBy(r => r.Text).ToList().ForEach(r => list.Add(
new SelectListItem { Text = r.Text, Value = r.Value.ToString() }));
}
}
catch (Exception e)
{ }
//add <select> to first item
list.Insert(0, new SelectListItem { Text = "", Value = "" });
return list;
}
}
public class HomeController : Controller
{
[HttpPost]
public ActionResult IndexValid9(FieldViewModel fieldViewModel)
{
//put breakpoint here to see selected values from both ddl, interrogate fieldViewModel
return View();
}
public ActionResult IndexValid9()
{
FieldViewModel fieldViewModel = new FieldViewModel();
return View(fieldViewModel);
}
表:
CREATE TABLE [dbo].[TableA](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Text] [varchar](20) NULL,
[Value] [int] NULL,
CONSTRAINT [PK_TableA] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
/****** Object: Table [dbo].[TableB] Script Date: 6/27/2017 3:59:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[TableB](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Text] [varchar](20) NULL,
[Value] [int] NULL,
CONSTRAINT [PK_TableB] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
SET IDENTITY_INSERT [dbo].[TableA] ON
GO
INSERT [dbo].[TableA] ([Id], [Text], [Value]) VALUES (1, N'tableaTxt', 1)
GO
INSERT [dbo].[TableA] ([Id], [Text], [Value]) VALUES (2, N'tableaTxt2', 2)
GO
SET IDENTITY_INSERT [dbo].[TableA] OFF
GO
SET IDENTITY_INSERT [dbo].[TableB] ON
GO
INSERT [dbo].[TableB] ([Id], [Text], [Value]) VALUES (1, N'tablebTxt', 1)
GO
INSERT [dbo].[TableB] ([Id], [Text], [Value]) VALUES (2, N'tablebTxt2', 2)
GO
SET IDENTITY_INSERT [dbo].[TableB] OFF
GO
答案 1 :(得分:0)
验证逻辑通常使用数据注释在View Model类中实现。但是,对于您的情况,您可以使用自定义验证属性,如下所示
public class OnlyOneValueAttribute : ValidationAttribute
{
public string TheOtherPropertyName { get; private set; }
public OnlyOneValueAttribute(string theOtherPropertyName)
{
TheOtherPropertyName = theOtherPropertyName;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var theProperty = validationContext.ObjectType.GetProperty(validationContext.MemberName);
var theValue = theProperty.GetValue(validationContext.ObjectInstance, null) as string;
var theOtherProperty = validationContext.ObjectType.GetProperty(TheOtherPropertyName);
var theOtherValue = theOtherProperty.GetValue(validationContext.ObjectInstance, null) as string;
if (string.IsNullOrEmpty(theValue) && !string.IsNullOrEmpty(theOtherValue) || !string.IsNullOrEmpty(theValue) && string.IsNullOrEmpty(theOtherValue))
{
return ValidationResult.Success;
}
return new ValidationResult(ErrorMessage);
}
}
然后您可以在模型中使用它
public class Order
{
public int OrderID { get; set; }
[OnlyOneValue(nameof(Field2))]
public string Field1 { get; set; }
[OnlyOneValue(nameof(Field1))]
public string Field2 { get; set; }
//other properties
}
在您的控制器中,您可以测试您的模型状态有效性
[HttpPost]
public ActionResult Test(Order model)
{
if (ModelState.IsValid)
{
//OK logic
}
return View();
}
但是,为了方便用户使用,我建议您查看此用例的实现。
希望这有帮助。
答案 2 :(得分:0)
如果验证规则是业务逻辑/需求的一部分,那么它应该在后端/服务器端实现。请记住,用户可以使用postman等工具将数据发布到您的路线,从而绕过您的UI / View验证。显示/隐藏输入的Javascript / UI验证是您可以采取的额外步骤,以便您的用户更轻松。如果此验证仅发生在应用程序的某个位置,我会保持简单,愚蠢(KISS)并在控制器内部进行验证:
[HttpPost]
public ActionResult Create(OrderViewModel order)
{
var bothFieldsAreEmpty = string.IsNullOrEmpty(order.Field1) && string.IsNullOrEmpty(order.Field2);
var bothFieldsAreFilled = !string.IsNullOrEmpty(order.Field1) && !string.IsNullOrEmpty(order.Field2);
if (bothFieldsAreEmpty || bothFieldsAreFilled)
{
ModelState.AddModelError("", "Please select either Field1 or Field2, not both.");
}
if (ModelState.IsValid)
{
// Do something
}
return View(order);
}