C# 在ASP.NET MVC解决方案中,从我的域对象重构表示代码的最佳方法是什么?
我刚刚接手了一个ASP.NETMVC项目,需要进行一些重构,但我想获得一些关于最佳实践的想法/建议 该站点有一个SQLServer后端,下面是对解决方案中项目的回顾:C# 在ASP.NET MVC解决方案中,从我的域对象重构表示代码的最佳方法是什么?,c#,html,asp.net-mvc,refactoring,domain-object,C#,Html,Asp.net Mvc,Refactoring,Domain Object,我刚刚接手了一个ASP.NETMVC项目,需要进行一些重构,但我想获得一些关于最佳实践的想法/建议 该站点有一个SQLServer后端,下面是对解决方案中项目的回顾: 域对象(每个数据库表一个类) 域orm(将代码从对象映射到数据库) 模型(业务逻辑) MVC(常规ASP.NET MVC web设置) ----控制器 ----视图模型 ----观点 ----剧本 我看到的第一个“问题”是,虽然域对象类在计算字段周围有一些额外的“get”属性,但域对象中有一些表示代码。例如,在DomainOb
- 域对象(每个数据库表一个类)
- 域orm(将代码从对象映射到数据库)
- 模型(业务逻辑)
- MVC(常规ASP.NET MVC web设置) ----控制器 ----视图模型 ----观点 ----剧本
public class Person
{
public virtual string NameIdHTML
{
get
{
return "<a href='/People/Detail/" + Id + "'>" + Name + "</a> (" + Id + ")";
}
}
}
公共类人物
{
公共虚拟字符串名称IDHTML
{
得到
{
返回“(“+Id+”)”;
}
}
}
显然,在域对象中包含HTML生成的内容似乎是错误的
重构方法:
我喜欢TBD的评论。这是错误的,因为您将域关注点与UI关注点混为一谈。这会导致一个可以避免的耦合 至于你建议的解决方案,我一个都不喜欢
要为这个问题提供一个完美的答案并不容易。尽管层的完全分离是可取的,但它通常会导致许多无用的工程问题 尽管每个人都同意这样一个事实,即业务层对表示层/UI层一定不太了解,但我认为,让it知道这些层确实存在是可以接受的,当然没有太多的细节 一旦声明了这一点,就可以使用一个未充分使用的接口:。这是使用的接口 例如,您可以先定义Person类,如下所示:
public class Person : IFormattable
{
public string Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
// reroute standard method to IFormattable one
return ToString(null, null);
}
public virtual string ToString(string format, IFormatProvider formatProvider)
{
if (format == null)
return Name;
if (format == "I")
return Id;
// note WebUtility is now defined in System.Net so you don't need a reference on "web" oriented assemblies
if (format == "A")
return string.Format(formatProvider, "<a href='/People/Detail/{0}'>{1}</a>", WebUtility.UrlEncode(Id), WebUtility.HtmlDecode(Name));
// implement other smart formats
return Name;
}
}
string.Format("{0:A}", myPerson);
string.Format("{0:A/People/Detail/}", person)
public class Address : IFormattable
{
public string Recipient { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
....
public virtual string ToString(string format, IFormatProvider formatProvider)
{
// http://stackoverflow.com/questions/3179716/how-determine-if-application-is-web-application
if ((format == null && InWebContext) || format == "H")
return string.Join("<br/>", Recipient, Line1, Line2, ZipCode + " " + City, Country);
return string.Join(Environment.NewLine, Recipient, Line1, Line2, ZipCode + " " + City, Country);
}
}
@model Person
@Html.ActionLink(Model.Name, "Detail", "People", new { id = Model.Id }, null) ( @Html.DisplayFor(p => p.Id) )
或者使用MVC的。NET中有许多类支持IFormattable(例如StringBuilder)
您可以优化系统,并改为执行以下操作:
public virtual string ToString(string format, IFormatProvider formatProvider)
{
...
if (format.StartsWith("A"))
{
string url = format.Substring(1);
return string.Format(formatProvider, "<a href='{0}{1}'>{2}</a>", url, WebUtility.UrlEncode(Id), WebUtility.HtmlDecode(Name));
}
...
return Name;
}
因此,您不需要在业务层中硬编码url。在web作为表示层的情况下,通常必须以这种格式传递CSS类名,以避免业务层中的硬编码样式。事实上,您可以提出非常复杂的格式。毕竟,这是对对象所做的事情,比如你仔细想想
您甚至可以更进一步,使用一些ambiant/static属性来告诉您是否在web上下文中运行,以便它自动工作,如下所示:
public class Person : IFormattable
{
public string Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
// reroute standard method to IFormattable one
return ToString(null, null);
}
public virtual string ToString(string format, IFormatProvider formatProvider)
{
if (format == null)
return Name;
if (format == "I")
return Id;
// note WebUtility is now defined in System.Net so you don't need a reference on "web" oriented assemblies
if (format == "A")
return string.Format(formatProvider, "<a href='/People/Detail/{0}'>{1}</a>", WebUtility.UrlEncode(Id), WebUtility.HtmlDecode(Name));
// implement other smart formats
return Name;
}
}
string.Format("{0:A}", myPerson);
string.Format("{0:A/People/Detail/}", person)
public class Address : IFormattable
{
public string Recipient { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
....
public virtual string ToString(string format, IFormatProvider formatProvider)
{
// http://stackoverflow.com/questions/3179716/how-determine-if-application-is-web-application
if ((format == null && InWebContext) || format == "H")
return string.Join("<br/>", Recipient, Line1, Line2, ZipCode + " " + City, Country);
return string.Join(Environment.NewLine, Recipient, Line1, Line2, ZipCode + " " + City, Country);
}
}
@model Person
@Html.ActionLink(Model.Name, "Detail", "People", new { id = Model.Id }, null) ( @Html.DisplayFor(p => p.Id) )
公共类地址:可附加
{
公共字符串收件人{get;set;}
公共字符串Line1{get;set;}
公共字符串第2行{get;set;}
公共字符串ZipCode{get;set;}
公共字符串City{get;set;}
公共字符串国家{get;set;}
....
公共虚拟字符串到字符串(字符串格式,IFormatProvider formatProvider)
{
// http://stackoverflow.com/questions/3179716/how-determine-if-application-is-web-application
if((格式==null&&InWebContext)| |格式==“H”)
返回字符串。Join(“
”,收件人,第1行,第2行,ZipCode+”+城市,国家);
返回字符串.Join(Environment.NewLine,Recipient,Line1,Line2,ZipCode+“”+城市,国家);
}
}
我自己也在努力解决这个问题。当视图中的代码比HTML更基于逻辑时,我创建了一个增强版的HtmlBuilder。我扩展了某些域对象,以自动打印出这个助手,其内容基于域之外的内容
AddressViewModel.cshtml
@Html.DisplayFor(m => m.Address)
@Html.EditorFor(m => m.Address)
@Html.DisplayFor(m => m.Address, new { show_property_name = false, ... })
@ {
var showPropertyName = ViewData.ContainsKey("show-property-name") ? (bool)ViewData["show-property-name] : true;
...
}
@if(showPropertyName)
{
@Html.TextBoxFor(m => m.PropertyName)
}
[UIHint("PostalAddress")]
public AddressViewModel Address { get; set; }
public static class BusinessToHtmlHelper {
public static MvcHtmlString FromBusinessObject( this HtmlHelper html, Person person) {
string personLink = html.ActionLink(person.Name, "Detail", "People",
new { id = person.Id }, null).ToHtmlString();
return new MvcHtmlString(personLink + " (" + person.Id + ")");
}
public static MvcHtmlString FromBusinessObject( this HtmlHelper html,
Department department) {
string departmentLink = html.ActionLink(department.Name, "Detail", "Departments",
new { id = department.Id }, null).ToHtmlString();
return new MvcHtmlString(departmentLink + " (" + department.Id + ")");
}
}
@person.NameIdHTML
@Html.FromBusinessObject(person)
@model Person
@Html.ActionLink(Model.Name, "Detail", "People", new { id = Model.Id }, null) ( @Html.DisplayFor(p => p.Id) )
@Html.DisplayFor(m => m.Person)
public static class BusinessToHtmlHelper {
public static MvcHtmlString FromBusinessObject<T>( this HtmlHelper<T> html, Person person) {
return html.DisplayFor( m => person );
}
//...
}
public static class PersonViewExtensions
{
const string NameAndOnePhoneFormat="{0} ({1})";
public static string NameAndOnePhone(this Person person)
{
var phone = person.MobilePhone ?? person.HomePhone ?? person.WorkPhone;
return string.Format(NameAndOnePhoneFormat, person.Name, phone);
}
}