ASP C#如何编写简洁的GUI代码

时间:2009-04-06 09:49:59

标签: c# user-interface refactoring

大约几个月我正在编写ASP C#。我总是在事件中编写很多代码,在load事件中我检查查询字符串是否有效数据。这是我在我的一个项目中的一些示例代码:

protected void Page_Load(object sender, EventArgs e)
{
    if (Controller.Manual == null)
    {
        Response.Redirect("login.aspx");
    }

    lblLocation.Text = "<a href='viewdocument.aspx'>" + Controller.Manual.Title + "</a>";

    if (Request.QueryString["gchap"] != null)
    {
        if (Controller.IsNumeric(Request.QueryString["gchap"].ToString()))
        {
            genchap = Convert.ToInt32(Request.QueryString["gchap"]);

            FillGeneralList();

            SetChapterTitle();
        }
    }
    if (Request.QueryString["qchap"] != null)
    {
        if (Controller.IsNumeric(Request.QueryString["qchap"].ToString()))
        {
            qualchap = Convert.ToInt32(Request.QueryString["qchap"]);

            FillQualityList();

            SetChapterTitle();
        }
    }

    // Check document Id is set (did)
    if (Request.QueryString["did"] != null)
    {
        if (Controller.IsNumeric(Request.QueryString["did"].ToString()))
        {
            docId = Convert.ToInt32(Request.QueryString["did"]);

            DetermineView();
        }
    }

}

我知道必须有一种方法可以更简洁的方式实现这一目标。这只是加载事件。在其他事件上,例如click和onchange事件,我有类似的代码。我认为这是意大利面条代码并没有很好的安排。那么你能告诉我如何安排我的代码吗?

编辑:

我想知道的是,是否有更简洁的方法,比方说,填写一个列表框?我在哪里检查查询字符串值是否有有效数据?我在哪里检查(输入/查询字符串)数据是否是数字?你应该在哪里放置验证Querystring的代码?还在加载事件中?

5 个答案:

答案 0 :(得分:4)

我对ASP.NET网站的一些组织问题感到痛苦。我在几个项目中都有类似的代码。

如果您可以选择框架,那么您可以查看ASP.NET MVC。这使您可以在View(Html),控制器(所有操作和业务逻辑)和Model(数据库)之间进行清晰的分离。这样你的代码隐藏文件就没有代码了,它在控制器中保持良好和整洁。

答案 1 :(得分:3)

尝试使用TryParse(for example),您可以简化所有类似

的代码
xx.IsNumeric(Request.QueryString["qchap"].ToString())

Convert.ToInt32(Request.QueryString["gchap"]);

并减少对Request.QueryString变量的调用次数

您可以尝试类似

的内容

原始代码

if (Request.QueryString["gchap"] != null)
{
    if (Controller.IsNumeric(Request.QueryString["gchap"].ToString()))
    {
        gchap = Convert.ToInt32(Request.QueryString["gchap"]);

        FillGeneralList();

        SetChapterTitle();
    }
}

<强>建议

int? gchap; //nullable types thanks Richard :D
if (!int.TryParse(Request.QueryString["gchap"], out id)) {gchap = null};

if (gchap != null) {
     FillGeneralList();
     SetChapterTitle();
}
// you could make this neater with your own little method

看一下这篇文章How do you test your Request.QueryString[] variables?

答案 2 :(得分:2)

尝试在单独的函数中捕获重复代码。 (qchap / gchap)

e.g:

qualchap = ConvertFillAndSet(Request.Querystring["qchap"]);
genchap = ConvertFillAndSet(Request.QueryString["gchap"]);

private int ConvertFillAndSet(string qrystring)
{
  int numberToReturn = 0;      

  //if the conversion was ok -> true, else false
  if (Int32.TryParse(qrystring,numberToReturn))
  {
    FillQualityList();
    SetChapterTitle();
  }

  //returns 0 if tryparse didn't work
  return numberToReturn;
}

答案 3 :(得分:2)

从哪里开始。不幸的是,尽管有其他评论,但你并没有真正写出任何特定的“网络表单”。因此,转向MVC并不会让你的代码变得更好。


1请勿滚动您自己的身份验证:除非您有令人信服的理由,否则请使用forms authentication。使用表单身份验证时,您无需在每个页面上编写代码来检查您是否已登录。框架会为您处理。


2 Learn使用server controls

另外,正如其他人写的那样,你不应该在代码中编写html,特别是对于那些微不足道的东西。 Web表单也不会让你这样做。

  <!-- this is in MyPage.aspx -->
  <asp:HyperLink id="viewLink" runat="server" />

  // in the code-behind file MyPage.aspx.cs
  viewLink.NavigateUrl = "~/viewdocument.aspx";
  viewLink.Text = Controller.Title;

如果您要坚持使用网络表单,则需要熟悉ASP.Net Page life-cycle


3您的代码需要重构。无论是Web表单,php还是MVC。这里有一些基本的重构,而这些都不是.net特定的。我将逐步完成这些步骤。

// this may be a good candidate for an extension method
int? ConvertNullable(string nullableInt) {
  if( string.IsNullOrEmpty(nullableInt) )
    return null;

  int value;
  if( Int32.TryParse(nullableInt, out value) )
    return value;

  return null;
}

然后允许你写。

int genchap? = ConvertNullable(Request.QueryString["gchap"]);
int qualchap? = ConvertNullable(Request.QueryString["qualchap"]);
int docId? = ConvertNullable(Request.QueryString["did"]);

FillQualityList(genchap,qualchap);
SetChapterTitle(genchap,qualchap);
DetermineView(docId);

但是传递很多原语很容易出错,所以有时我们会创建一个小类来封装数据,在这种情况下是页面初始化信息。

class ChapterView
{
  public int? GenChapter {get; set;}
  public int? QualChapter {get; set;}
  public int? DocumentId {get; set;}
}

private ChapterView GetChapterView()
{
  return new ChapterView
  {
    GenChapter = ConvertNullable(Request.QueryString["gchap"]),
    QualChapter = ConvertNullable(Request.QueryString["qualchap"]),
    DocumentId = ConvertNullable(Request.QueryString["did"])
  }
}

请注意,我不知道GenChap和QualChap是什么,但它们有点简洁,你可以完成重构,使它们在代码中更具可读性。但即使没有更好的名字,我们现在也有更易读的代码。

ChapterView chapterView = GetChapterView();

FillQualityList(chapterView);
SetChapterTitle(chapterView);
DetermineView(chapterView);

最后,您可能会确定每次执行页面时都不需要调用它来从查询字符串中读取。如果您已阅读Asp.Net Page LifeCycle,则您知道事件可能会发生变化GenChapter或其他影响页面呈现方式的内容。您可能会发现在PreRender中设置视图更好,而不是一遍又一遍地调用FillQualityList。

ChapterView chapterView;

Page_Load()
{
  if( !IsPostback )
  {
    ChapterView chapterView = GetChapterView();
  }
  else
  {
    chapterView = (ChapterView) ViewState["chapterview"];
  }
}

NextChapter_Click()
{
  chaperView.NextChapter();
}

Page_PreRender()
{
  FillQualityList(chapterView);
  SetChapterTitle(chapterView);
  DetermineView(chapterView);}

  // make sure class is marked [Serializable]
  ViewState["chapterview"] = chapterView; 
}

答案 4 :(得分:1)

你应该遵循分层方法。即:将所有数据访问代码放入数据访问层,将所有业务逻辑(也包括验证)放在业务层中,将所有模型代码放入业务对象层

最后是ui - 尽量不要在代码中生成html标记。此外,始终为您的aspx页面创建一个根类,其中已经实现了常用方法。然后为每个其他aspx页面子类化这个根类

如果你要在你的c#代码中硬编码html标记 - 我可以向你保证这会导致很多混乱(基于我自己的经验)

但有些情况下你根本无法避免它。对于这种情况 - 这就是我所做的 - 我摆脱了背后的代码,只是把代码放在我的aspx / ascx文件本身。这样,当我必须根据永不停止的客户端请求更改我的UI时,我不必重新编译我的代码 - 我只是在登台/生产服务器上替换我的aspx / ascx文件。

你知道客户是怎么做的:嗯,你可以让黑色条看起来有点像灰色,你可以增加行之间的间距,你可以改变这个超链接的文本......像这样的请求似乎永远不会结束: - )