[转载]ASP.NET的SEO:Linq to XML---网站地图和RSS Feed

mikel阅读(1108)

[转载]ASP.NET的SEO:Linq to XML—网站地图和RSS Feed – 自由飞 – 博客园.

本 系列目录

网站地图的作用是让搜索引擎尽快的,更多的收录网站的各个网页。

这里我们首先要明白一个基本的 原理,搜索引擎的爬行方式。整个互联网就像一张纵横交错的“网”:网的各个节点就是各个网页,而各个网页之间通过url相互连接。蜘蛛可以从一个网页出 发,通过该网页上的url,爬到另一个网页;再通过另一个网页上的url,再爬到更多的网页……,以此类推。但如果是一个新发布的网站,可能就没有其他 url指向它,那么它就永远不会被“爬到”(收录)。为了解决这个问题,新站可以自己主动向搜索引擎提交url,申请蜘蛛前来抓取(Google申请网 址:),但申请时一般只会提交一个主页的url。

为了让所有的url(尤其是动态生成的)都能被蜘蛛快捷便利的检索到,我们就需要提供一 个全面完整、架构清晰和更新及时的网站地图。(网站地图的更多信 息)。

和处理重复内容的robots.txt文件,我们通过.ashx文件来生成一个基于sitemaps.org的 xml格式的网站地图。网站地图生成之后,我们就可以向Google等搜索引擎提交。大量的文章证实,提交网站地图将极大的提高网站的收录速度和深度。其 他几乎所有的SEO方法,都有可能效果难以证实、失效甚至带来副作用,但提交网站地图除外!

Linq to XML为我们带来了近乎完美的操作体验。

WebSite

<%@ WebHandler Language=C# Class=website %>

using System;
using System.Web;
using System.Xml;
using System.Xml.Linq;
using System.Linq;

public class website : IHttpHandler {

public void ProcessRequest (HttpContext context) {

context.Response.ContentType = text/xml;

//文件的声明信息, 第第三个参数standalone的值yes 表示这个 XML 文档是自包含的(self-contained)而不依赖于外部所定义的一 个 DTD.
XDeclaration declaration = new XDeclaration(1.0, UTF-8, yes);
context.Response.Write(declaration);

//XML文件的命名空间
XNamespace ns = http://www.google.com/schemas/sitemap/0.84;
XElement siteMap = new XElement(ns + urlset);

string fixedUrl = http://www.freeflying.com/article;
string wholeUrl = string.Empty;

//循环取出数据,转换成XML节点
foreach (var item in Articles.GetArticles())
{
XElement url = new XElement(url);

wholeUrl = string.Format({0}?id={1}&catelog={2},fixedUrl,item.ID,item.Catelog);
XElement loc = new XElement(loc, wholeUrl);
XElement lastmod = new XElement(lastmod, item.LastMod.AddDays(23).ToShortDateString());
XElement changefreq = new XElement(changefreq, item.Frequency);
XElement priority = new XElement(priority, item.Weight);

url.Add(loc, lastmod, changefreq, priority);

siteMap.Add(url);
}

//最后输出整个xml文件
context.Response.Write(siteMap);
}

public bool IsReusable {
get {
return false;
}
}

}

同 样还将使用到xml技术的还有RSS

RSS

<%@ WebHandler Language=C# Class=rss %>

using System;
using System.Web;
using System.Xml;
using System.Xml.Linq;

public class rss : IHttpHandler {

public void ProcessRequest (HttpContext context) {
context.Response.ContentType = text/xml;

context.Response.Write(<?xml version=\1.0\ encoding=\UTF8\ ?>);

XElement rssFeed = new XElement(rss, new XAttribute(version,2.0));

string fixedUrl = http://www.freeflying.com/article;
string wholeUrl = string.Empty;

XElement channel = new XElement(channel,
new XElement(title, freeflying),
new XElement(link, fixedUrl),
new XElement(description,the website for dream flying freely),
new XElement(pubDate,DateTime.Now.ToString())
);

foreach (var article in Articles.GetArticles())
{
XElement item = new XElement(item);

XElement title = new XElement(title, article.Title);

wholeUrl = string.Format({0}?id={1}&catelog={2}, fixedUrl, article.ID, article.Catelog);
XElement link = new XElement(link, wholeUrl);

XElement description = new XElement(description, article.Description);

XElement pubDate = new XElement(pubDate, article.LastMod.ToString());

item.Add(title,link,description,pubDate);

channel.Add(item);
}

rssFeed.Add(channel);

context.Response.Write(rssFeed);

}

public bool IsReusable {
get {
return false;
}
}

}

模拟数据

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Web.UI.MobileControls;
using System.Collections.Generic;

/// <summary>
/// Summary description for Articles
/// </summary>
public class Articles
{
public Articles()
{
//
// TODO: Add constructor logic here
//
}

public static List<Article> GetArticles()
{
return new List<Article>(){
new Article(234, blog, DateTime.Now.AddDays(23), Freq.none, 0.8, ASP.NET SEO, articles about SEO in ASP.NET),
new Article(267, blog, DateTime.Now.AddDays(245), Freq.daily, 0.6, ado.net pro,about the dataset usage),
new Article(653, news, DateTime.Now.AddDays(45), Freq.daily, 1,CLR via C#,notebook about this book)
};
}

}

public class Article
{
public int ID;
public string Catelog;
public DateTime LastMod;
public double Weight;
public Freq Frequency;
public string Title;
public string Description;

public Article(int id, string catelog, DateTime lastMod, Freq frequency, double weight, string title, string description)
{
ID = id;
Catelog = catelog;
LastMod = lastMod;
Weight = weight;
Frequency = frequency;
Title = title;
Description = description;
}
}

public enum Freq
{
none = 1,
daily = 2,
weekly = 3,
}

[原创]nvelocity模板调用.NET类的方法代码

mikel阅读(1476)

最近利用NVelocity+MVC进行开发过程中,发现NVelocity没有四舍五入的函数,利用js进行页面处理又太慢,如果可以调用.NET类的方法就太完美了。

于是Google了一下,发现篇Velocity调用Java代码的文章:

velocity模板开发中减法 加法

既然NVeclocity是从Velocity来的,自然少不了这个功能了,于是将ASP.NET的代码修改如下:

public class MatchTool

{

/// <summary>

/// 四舍五入

/// </summary>

/// <param name="d"></param>

/// <param name="decimals"></param>

/// <returns></returns>

public Decimal Round(decimal d, int decimals)

{

return System.Math.Round(d,decimals);

}

}

//添加C#的Math数字计算实例给模板用于四舍五入

AddContext("MathTool",new MatchTool());

由于C#的System.Math是静态类型,不能实例化赋值给模板标签$MathTool,于是给包装了一下,实例化了个MathTool类封装了Round方法,于是将它的实例赋值给模板标签MathTool

模板代码调用代码如下:

$MathTool.Round($order.UnitPrice,2)

另外NVelocity也可以调用.NET的String类型的方法,例如String类型的CutString方法

代码如下:

$Str.Cutstring(0,20) 截取20个字符

[转载]项目开发总结:前端开发部分总结[兼容性、DOM操作、跨域等]

mikel阅读(987)

[转载]项目开发总结:前端开发部分总结[兼容性、DOM操作、跨域等]

项目背景:.Net 3.5+MySQL+JQuery+WebService

在公司做这个项目已经6个多月了,总结一些问题,也算 是抛砖引玉吧,希望园子里更多的朋友一起分享一些技巧。

1、 WebService方法返回值不能为void。

当 WebService方法返回值为void时,FF和Chrome会持续等待,认为这个请求没有结束,而在IE中一切是正常的。

2、 当input的type=”button”时或者使用button时,点击后会触发form的submit。

当时查找页面刷新的问题找了很 久,最后才发现是button会自动触发form的submit,导致当前页面的刷新。

3、js设置document.domain只能从 二级域名设置到顶级域名。

比如访问moozi.cnblogs.com,可以在这个页面中写 document.domain=’cnblogs.com’;如果把域设置为cnblogs.com之后,无法再使用 document.domain=’moozi.cnblogs.com’;。

4、使用DOM片段创建iframe,当跨域时,不能用js 写iframe的域。

比如你在moozi.cnblogs.com/test.html页面用js把域设置为 document.domain=’cnblogs.com’,而此时你再用var ifrm=createElement(‘iframe’) ,这时将不能用js设置iframe的域也为’cnblogs.com’,只能让ifrm.src=’test2.htm’,并在test2.htm中设 置域document.domain=’cnblogs.com’。

5、当你修改过当前域的时候,CKEditor是正常的,而 tinyMCE需要重新设置域。

CKEditor能自动识别当前域,并不出错。tinyMCE需要人为的设置。同时,如果你是用 CKFinder上传文件,而需要修改它的输入代码,不然会因为域不同而出现没有权限的错误提示。

6、使用tinyMCE,尽管你的初始化 代码只有一句,但是可能出现多次初如化。发生原因未知,在不确定的情况下会出现此BUG。

7、开发js组件的时候,要时刻注意闭包 和this的指代,这方面之前吃了不少亏。

8、将字符串转换成JQuery对象时,要注意字符串html代码的闭合标签。

比 如:var html='<span>test</span>&nbsp;’var jqEl=$(html);此时,jqEl会把html里的’&nbsp;’丢掉。

9、jQuery1.2.6和 jQuery1.3在细节的处理上有一些区别。

jQuery1.2.6处理hasClass(‘.className’)会出错,而 jQuery1.3不会。

10、尽量少用jQuery的each,多用js原生的代码,性能较高。

———————-

先 写到这里吧…继续更新

[转载]Asp.net MVC并不仅仅只是Linq to SQL

mikel阅读(1591)

[转载]【译】Asp.net MVC并不仅仅只是Linq to SQL – CareySon – 博客园.

很多ASP.NET的教程中的示例代码使用的数据访问方法是Linq to SQL或是Entity Framework。我在www.asp.net的论坛上看到很多关于讨论是否有其他替代的数据库访问方式,回答 是:当然有。这篇文章就讲述了使用Ado.Net作为数据访问层来实现一个典型的增删查改程序。

由于是以练习作为目的,那我就不妨借用Spaanjaar’s 的N层构架文章(Building Layered Web Applications with Microsoft ASP.NET 2.0.)的构架方式。我强烈推荐你阅读他 的系列文章,如果嫌太长起码也得看完前两部分,这样就能对N-Layer构架有个基本的认识。N-Layer构架的三个关键层分别为:业务对象层,业务逻 辑层和数据访问层。而其数据访问层会几乎不加改变的包含在本文的MVC项目中,Spaanjaar的文件详细描述了各个层是如何组织的。这篇文章仅仅讲述 各个层所扮演的角色,但是不会深入到代码的细节中。

首先,我们来看Imar提供的程序,这是一个具有典型增删查改的程序,这个程序允许用户管理联系人,包括联系人的地址,电话,email。它能增,删, 查,改任何实体。

程序内包括的实体有:ContactPersons, PhoneNumbers, Addresses EmailAddresses.他们都隶属于程序的业务对象(BO)层。上述的每一个类都包含可以获取或者赋值的属性,但并不包含任何方法。而所有方法存 放于业务逻辑层(BLL)中的对应类中。在业务对象层和业务逻辑层的实体和实体manger是一对一的关系,在业务逻辑层中类包含的方法都会返回业务对象 层(BO)的实例,或是实例集合,或者保存实例(更新或是添加),或是删除实例。业务逻辑层(BLL)中也可以包含一些业务规则验证,安全性检查的代码。 但在本篇文章为了简便起见,就不添加这些了。如果你对业务规则和安全性有兴趣的话,可以去看Imar文章的6 part series

最后一层是数据访问层(DAL),同样,DAL层的类也和业务逻辑层(BLL)内的类有着一对一的关系,在BLL层的类中会调用相关DAL层中的方法。而 在这些层中,只有DAL层需要知道利用什么技术(linq,entity framework..)保存业务实体。在本例中,使用SQL Server Express数据库和Ado.net。而这样分层的思想是如果你需要更换数据源(XML,oracle,更或者是Web Service甚至是Linq to SQL或者其他ORM框架),因为DAL层给BLL层暴漏的方法的签名是一致的,所以只需要更换DAL层即可。而为了保证所有DAL的实现有着同样的签 名,则利用接口即可。但我想或许是未来帖子中讨论的话题了吧。

MVC构架

已经有很多优秀的文章中已经探讨了MVC程序的构架,所以本篇文章就不再累述相关细节了。如果想要了解更多,我推荐访问Asp.net MVC官方站点.简单二代说,M代表Model,也是包含 BO,BLL,DAL的地方,V代表View,也是UI相关开发的部分,或者说是用户看到的部分,C是Controller的简写,也是控制用户请求与程 序回复的部分。如果用户点击了一个指向特定地址的按钮,请求会和Controller的Action(类的方法)进行匹配,而Action负责处理请求, 并返回响应。通常情况下是一个新的View,或者是更新现有的View。

下面用Visual Studio创建一个MVC应用程序并删除默认的View和Controller,然后将Imar的程序中的Bo,Bll和DAL复制到这个MVC程序的 Model内,我还复制了响应的数据库文件和Style.css。

我还做了 一些其他的修改,把数据库连接字符串添加到Web.Config中。除此之外,我还将复制过来的代码的命名空间做了响应的调整并把DAL层的代码升级到了 3.0.虽然这并不是必须的。做完这些,我按Ctrl+Shift+F5来测试是否编译成功。——————

Controller

我 添加了4个Controller(Visual Studio附带的默认Controller已经被删除),和四个实体类相匹配。它们分别为:ContactController, PhoneController, AddressController and EmailController。

每个 Controller都含有四个Action:List, Add, Edit and Delete。首先需要在Global.exe中为这些Action注册这些路由。

public static void RegisterRoutes(RouteCollection routes)
{
  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

  routes.MapRoute(
      "Default",                                              
      "{controller}/{action}/{id}",                           
      new { controller = "Contact", action = "List", id = " " }  
  );
}

默认的View会显示所有联系人,BLL层中的ContactPersonManager类内的GetList()方法会获取所有联系人的数 据,响应的List() Action代码如下:

public ActionResult List()
{
  var model = ContactPersonManager.GetList();
  return View(model);
}

强类型View

整个实例代码中,我都会使用强类型的View,因为这样不仅可以使用intellisense(智能提示)的好处,还不必依赖于使用String作为索引 值的ViewData。为了让代码更加有序,我添加了一些命名空间到web.config中的<namespaces>节点,这些都是我用来 替换Imar代码的方式:

<namespaces>
<add namespace="System.Web.Mvc"/>
<add namespace="System.Web.Mvc.Ajax"/>
<add namespace="System.Web.Mvc.Html"/>
<add namespace="System.Web.Routing"/>
<add namespace="System.Linq"/>
<add namespace="System.Collections.Generic"/>
<add namespace="ContactManagerMVC.Views.ViewModels"/>
<add namespace="ContactManagerMVC.Models.BusinessObject"/>
<add namespace="ContactManagerMVC.Models.BusinessObject.Collections"/>
<add namespace="ContactManagerMVC.Models.BusinessLogic"/>
<add namespace="ContactManagerMVC.Models.DataAccess"/>
<add namespace="ContactManagerMVC.Models.Enums"/>
</namespaces>

上面代码意味着我可以在程序的任何地方访问上述命名空间。上面GetList()方法返回的类型是ContactPersonList,这个类型是 ContactPerson对象的集合,在显示List的View中的Page声明如下:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
    Inherits="System.Web.Mvc.ViewPage<ContactPersonList>" %>

我想你已经注意到了我使用了MasterPage,利用MasterPage,我借用了从Imar实例代码中的Css文件。用于显示 ContactPerson对象的HTML如下:

<table class="table">
    <tr>
      <th scope="col">Id</th>
      <th scope="col">Full Name</th>
      <th scope="col">Date of Birth</th>
      <th scope="col">Type</th>
      <th scope="col">&nbsp;</th>
      <th scope="col">&nbsp;</th>
      <th scope="col">&nbsp;</th>
      <th scope="col">&nbsp;</th>
      <th scope="col">&nbsp;</th>  
    </tr>
    <%
      if (Model != null)
      {
        foreach (var person in Model)
        {%>
    <tr>
      <td><%= person.Id %></td>
      <td><%= person.FullName %></td>
      <td><%= person.DateOfBirth.ToString("d") %></td>
      <td><%= person.Type %></td>
      <td title="address/list" class="link">Addresses</td>
      <td title="email/list" class="link">Email</td>
      <td title="phone/list" class="link">Phone Numbers</td>
      <td title="contact/edit" class="link">Edit</td>
      <td title="contact/delete" class="link">Delete</td>
    </tr>
    <%
        }
      }else{%>
    <tr>
      <td colspan="9">No Contacts Yet</td>
    </tr>  
     <% }%>
  </table>

我想你已经能发现强类型View的好处了吧,Model的类型是ContactPersonList,所以你可以任意使用 ContactPersonList的属性而不用强制转换,而强制转换错误只有在运行时才能被发现,所以这样省了不少事。

在做Html时,我小小的作弊了一下,我本可以使用vs对list自动生成的view,但我没有。因为我需要和Imar的css文件相匹配的html.所 以我运行了imar的程序,在浏览器中查看源代码,并把生成的html复制下来,imar使用GridView来生成列表,所以CSS会在运行时嵌入到 html代码中。我将这些css代码移到一个外部的css文件中。并给<th>和<td>元素添加了一些额外样式,你可以在代码 的下载链接中找到。

我还未一些表格的单元格添加了title属性。这些包含了访问其他action的链接。我希望用户在浏览电话本或者编辑或者删除电话本时页面不会post back,换句话说,我希望我的网站是ajax的。而title属性就发挥作用了。而“。link”这个css选择符可以让普通的文本看起来像超链接,也 就是有下划线和鼠标hover时出现小手。

JQuery AJax

在我们深入实现ajax功能的相关代码之前,下面3行代码是需要加入到html中:

<input type="button" id="addContact" name="addContact" value="Add Contact" />
<div id="details"></div>
<div id="dialog" title="Confirmation Required">Are you sure about this?</div>

第一行代码的作用是一个允许用户添加新联系人的按钮,第二行代码是一个空div,方便后面显示信息,第三行代码是JQuery modal 提示验证对话框的一部分,用于提示用户是否删除一条记录。

还需要在页面中添加3个js文件,第一个是主要的JQuery文件,其他两个分别是jQuery UI的核心js,以及date picker和modal dialog部分的js

<script src="../../Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
<script src="../../Scripts/ui.core.min.js" type="text/javascript"></script>
<script src="../../Scripts/jquery-ui.min.js" type="text/javascript"></script>

下面是我们生成后的列表显示视图以及完全的js代码:

<script type="text/javascript">
  $(function() {
    // row colours
    $('tr:even').css('background-color', '#EFF3FB');
    $('tr:odd').css('background-color', '#FFFFFF');
    // selected row managment
    $('tr').click(function() {
      $('tr').each(function() {
        $(this).removeClass('SelectedRowStyle');
      });
      $(this).addClass('SelectedRowStyle');
    }); 
    // hide the dialog div
    $('#dialog').hide();
    // set up ajax to prevent caching of results in IE
    $.ajaxSetup({ cache: false });
    // add an onclick handler to items with the "link" css class
    $('.link').live('click', function(event) {
      var id = $.trim($('td:first', $(this).parents('tr')).text());
      var loc = $(this).attr('title');
      // check to ensure the link is not a delete link
      if (loc.lastIndexOf('delete') == -1) {
        $.get(loc + '/' + id, function(data) {
          $('#details').html(data);
        });
      // if it is, show the modal dialog   
      } else {
        $('#dialog').dialog({
          buttons: {
            'Confirm': function() {
              window.location.href = loc + '/' + id;
            },
            'Cancel': function() {
              $(this).dialog('close');
            }
          }
        }); 
        $('#dialog').dialog('open');
        }
      }); 
      // add an onclick event handler to the add contact button
      $('#addContact').click(function() {
        $.get('Contact/Add', function(data) {
          $('#details').html(data);
        });
      }); 
    });
</script>

上面代码看起来让人望而却步,但实际上,使用jQuery,这非常简单。并且在上面代码中我多处加入了注释,代码一开始是用js代码是替换了数据源 控件默认呈现出来的隔行变色的颜色。然后我加入了使点击行点击时可以变色的代码。然后下面的代码是防止IE对页面进行缓存。如果不禁止了IE缓存,你会为 执行编辑或者删除以后,数据库改变了但页面却没有发生变化而撞墙的。

接下来的代码更有趣了,依靠live()方法可以确$选择器中所有匹配的元素都被附加了相应的事件,无论元素当前是否存在于页面中。比如说,当你点击了 Addresses链接,相应的结果就会在另一个表中出现:

上图中可以看出表中包含编辑和删除链接,如果不使用live()方法,相应的链接就不会被附加事件。所有具有class为link的元素都会被委派上 click事件。这个事件会首先获取到当前条目的id.以ContactPerson表为例,这个id就是ContactPersonId.在相应的子表 中,则id会是电话号码或者是email地址。这些都是需要传递给controller action作为参数进行编辑,删除,或者显示的。

你现在可以看出为什么我为每个单元格加上title属性了吧。title属性包含相关的route信息,而完全的url则把id附加到route作为 url.然后,上面js会做一个检查,来看route信息内是否包含delete,如果包含delelte,则弹出一个对话框来提示用户是否要删除。看, 是不是很简单?

最后,代码会为添加联系人按钮添加click事件,在文章的下部分我们再进行讨论

添加联系人以及自定义View Models

使用ASP.NET添加一条记录时,通常的做法是提供一个包含一系列输入框的form.对于ContactPerson类的大多属性来说,都是可以直接赋 值的,比如:姓,名字,生日。但是其中有一个属性却不能直接赋值–Type属性,这个值是从PersonType.cs(朋友,同事等)中的枚举类型中 选择出来的.这意味着用户只能从有限的几种选项中选择一种。可以用DropDwonList来实现,但是ContactPerson对象并不包含枚举类型 的所有选项,所以我们只能提供一个自定义版本的ContactPerson类传递给View.这也是为什么要用到自定义View Model

我看过很多关于在程序的哪里放置View Models的讨论,有些人认为自定义View Models是Model的一部分,但是我认为它和View紧密相关,View Models并不是MVC程序必不可少的一部分,也不能服用,所以它不应该放到Model中区。我把所有的View Model放入一个创建的ViewModel文件夹下,ContactPersonViewModel.cs的源代码如下:

using System;
using System.Collections.Generic;
using System.Web.Mvc;

namespace ContactManagerMVC.Views.ViewModels
{
  public class ContactPersonViewModel
  {
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public IEnumerable<SelectListItem> Type { get; set; }
  }
}

看上面类的最后一个属性,我将这个type属性设置成IEnumerable<SelectListItem>类型,这样就可以将Type绑 定到View中的Html.DropDownList了。

对应的,也要在Controller中添加2个action,第一个action使用AcceptVerbs(HttpVerbs.Get)标签,第二个 action使用AcceptVerbs(HttpVerbs.Post)标签,第一个方法用于从服务器向客户端传值,第一个方法处理从form提交的数 据。

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Add()
{
  var personTypes = Enum.GetValues(typeof (PersonType))
    .Cast<PersonType>()
    .Select(p => new
                   {
                     ID = p, Name = p.ToString()
                   });
  var model = new ContactPersonViewModel
                {
                  Type = new SelectList(personTypes, "ID", "Name")
                };
  return PartialView(model);
}


[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(ContactPerson person)
{
  ContactPersonManager.Save(person);
  return RedirectToAction("List");
}

上面第一个action的前几行代码将ContactType枚举类型转换成数组,数组中的每一个元素都是一个包含id和name属性的匿名对象,id是 枚举值,Name是和对应枚举匹配的constant值,ContactPersonViewModel然后进行初始化并且Type属性被赋值相应的类 型。我使用Partial View来添加联系人和使用ContactPersonViewModel类型的强类型,对应View部分的代码如下:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ContactPersonViewModel>" %>

<script type="text/javascript">
  $(function() {
  $('#DateOfBirth').datepicker({ dateFormat: 'yy/mm/dd' });
  });
</script>

<% using (Html.BeginForm("Add", "Contact", FormMethod.Post)) {%>
      <table>
        <tr>
          <td class="LabelCell">Name</td>
          <td><%= Html.TextBox("FirstName") %></td>
        </tr>
        <tr>
          <td class="LabelCell">Middle Name</td>
          <td><%= Html.TextBox("MiddleName") %></td>
        </tr>
        <tr>v
          <td class="LabelCell">Last Name</td>
          <td><%= Html.TextBox("LastName") %></td>
        </tr>
        <tr>
          <td class="LabelCell">Date of Birth</td>
          <td><%= Html.TextBox("DateOfBirth", String.Empty)%></td>
        </tr>
        <tr>
          <td class="LabelCell">Type</td>
          <td><%=Html.DropDownList("Type")%>
          </td>
        </tr>
        <tr>
          <td class="LabelCell"></td>
          <td><input type="submit" name="submit" id="submit" value="Save" /></td>
        </tr>
      </table>
<% } %>

在最上面的代码我使用了jQuery UI的Date picker插件作为DateOfBirth输入框的选择方式,而DateOfBirth的第二个参数保证这个textbox在初始状态下为空。此外,所 有的输入框对ContactPerson的对应属性名相同,这是为了确保默认的model binder不出差错,MVC还自动为ContactType枚举进行绑定。

负责响应Post请求的方法可以自动将Request.Form的值和ContactPerson对象的对应属性进行匹配,然后调用BLL层的 Save()方法,然后RedicrectToAction会让页面刷新最后调用List这个action.

编辑一个联系人

和前边一样,需要在Controller添加两个action来完成编辑,一个用于响应Get请求,另一个用于响应Post请求:

[AcceptVerbs(HttpVerbs.Get)]
    public ActionResult Edit(int id)
    {
      var personTypes = Enum.GetValues(typeof (PersonType))
        .Cast<PersonType>()
        .Select(p => new { ID = p, Name = p.ToString() });

      var contactPerson = ContactPersonManager.GetItem(id);
      var model = new ContactPersonViewModel
                    { 
                      Id = id,
                      FirstName = contactPerson.FirstName,
                      MiddleName = contactPerson.MiddleName,
                      LastName = contactPerson.LastName,
                      DateOfBirth = contactPerson.DateOfBirth,
                      Type = new SelectList(personTypes, "ID", "Name", contactPerson.Type)
                    };
      return PartialView(model);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(ContactPerson person)
    {
      ContactPersonManager.Save(person);
      return RedirectToAction("List");
    }

我们在前面已经看到jQuery是如何调用Edit这个action并把被编辑人的id作为参数进行传递的了,然后id用于通过众所周知的bll调用 DAL从数据库将联系人的详细信息取出来。在这个过程中ContactPersonViewModel被创建来返回从数据库取出的 值,SelectList的通过三个参数构造,第一个参数是Person的类型,第三个参数是DropDownList当前选择的值

partial view的代码和Add View几乎一样:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ContactPersonViewModel>" %>

<script type="text/javascript">
  $(function() {
    $('#DateOfBirth').datepicker({dateFormat: 'yy/mm/dd'});
  });
</script>

<% using (Html.BeginForm("Edit", "Contact", FormMethod.Post)) {%> 
     <table>
        <tr>
          <td class="LabelCell">Name</td>
          <td><%= Html.TextBox("FirstName") %></td>
        </tr>
        <tr>
          <td class="LabelCell">Middle Name</td>
          <td><%= Html.TextBox("MiddleName") %></td>
        </tr>
        <tr>
          <td class="LabelCell">Last Name</td>
          <td><%= Html.TextBox("LastName") %></td>
        </tr>
        <tr>
          <td class="LabelCell">Date of Birth</td>
          <td><%= Html.TextBox("DateOfBirth", Model.DateOfBirth.ToString("yyyy/MM/dd")) %></td>
        </tr>
        <tr>
          <td class="LabelCell">Type</td>
          <td><%= Html.DropDownList("Type")%></td>
        </tr>
        <tr>
          <td class="LabelCell"><%= Html.Hidden("Id") %></td>
          <td><input type="submit" name="submit" id="submit" value="Save" /></td>
        </tr>
      </table>
<% } %>

关键不同是DateOfBirth包含一个将生日信息转换更容易识别的方式,还有在提交按钮附近添加了一个Html.Hidden(),用于保存被 编辑用户的id。当然,form的action属性肯定是和Add的View不同。在Form中可以加一个参数用于告诉Action是Add View还是Edit View,这样就能减少代码的重复,但是在示例代码中我还是把他们分成了不同的action,来让职责划分的更清晰一些。

删除一个联系人

删除action就简单多了,并且不需要与之相关的View.仅仅是重新调用List这个action,被删除的数据就不复存在了。

public ActionResult Delete(int id)
{
  ContactPersonManager.Delete(id);
  return RedirectToAction("List");
}

上面代码是我对BLL和DAL做出改变的地方,原来的ContactPersonManager.Delete()方法的参数是Person的实例,而在 DAL中,只有id作为参数。我看不出传递整个对象给BLL,但BLL却只传递对象的唯一ID给DAL的意义所在,所以我将BLL的代码改成接受int类 型的参数,这样写起来会更简单。

当删除链接被点击时,调用jQuery的confirmation modal dialog:

如果点击取消,则什么事也不发生,如果点击确认,则链接就会指向响应的delete action.

管理集合

所有的集合–PhoneNumberList,EmailAddressLIst,AddressList被管理的方式如出一辙。所以,我仅仅挑选 EmailAddressLIst作为示例来说明方法,你可以下载示例代码来看其他部分。

首先,我们来看显示被选择联系人的email地址,这包含了controller中List这个Action:

public ActionResult List(int id)
{
  var model = new EmailAddressListViewModel
                {
                  EmailAddresses = EmailAddressManager.GetList(id),
                  ContactPersonId = id
                };
  return PartialView(model);
}

上面方法使用联系人的id作为联系人,并且返回一个自定义View Model—EmailAddressListViewModel.这也是将联系人的id传到View的方法:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<EmailAddressListViewModel>" %>
<script type="text/javascript">
  $(function() {
    $('#add').click(function() {
      $.get('Email/Add/<%= Model.ContactPersonId %>', function(data) {
        $('#details').html(data);
      });
    });
  });
</script>
<table class="table">
   <tr>
     <th scope="col">Contact Person Id</th>
     <th scope="col">Email</th>
     <th scope="col">Type</th>
     <th scope="col">&nbsp;</th>
     <th scope="col">&nbsp;</th>
   </tr>
   <%if(Model.EmailAddresses != null)
     {foreach (var email in Model.EmailAddresses) {%>
   <tr>
     <td><%= email.Id %></td>
     <td><%= email.Email %></td>
     <td><%= email.Type %></td>
     <td title="email/edit" class="link">Edit</td>
     <td title="email/delete" class="link">Delete</td>
   </tr>
        <%}
    }else
 {%>
   <tr>
     <td colspan="9">No email addresses for this contact</td>
   </tr>
 <%}%>
</table>
<input type="button" name="add" value="Add Email" id="add" />

你可以看出添加方法需要ContactPersonID作为参数,我们需要确保可以添加新的联系人到响应的联系人列表。编辑和删除方法也是如此–id参 数通过url传递到相关action.而所有的单元格都有title属性,这样就可以使用前面部署的live()方法:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Add(int id)
{
  var contactTypes = Enum.GetValues(typeof(ContactType))
    .Cast<ContactType>()
    .Select(c => new
    {
      Id = c,
      Name = c.ToString()
    });
  var model = new EmailAddressViewModel
                {
                  ContactPersonId = id,
                  Type = new SelectList(contactTypes, "ID", "Name")
                };
  return PartialView("Add", model);
}


[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(EmailAddress emailAddress)
{
  emailAddress.Id = -1;
  EmailAddressManager.Save(emailAddress);
  return RedirectToAction("List", new {id = emailAddress.ContactPersonId});
}

创建自定义View Model存在的目的是为了对现有的EmailAddress进行添加或编辑,这包括一些绑定 IEnumerable<SelectListItem>集合到Type dropdown的属性,上面两个Add不同之处在于他们的返回不同,第一个返回partial view,第二个返回List这个action.

集合中的每一个选在在一开始都会将id设为-1,这是为了保证符合”Upsert”存储过程的要求,因为Imar对于添加和删除使用的是同一个存储过程, 如果不设置成-1,则当前新建的联系人会更新掉数据库中的联系人。如果你想了解更多,请看他的文章。下面是添加email address的partial view:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<EmailAddressViewModel>" %>

<script type="text/javascript">
  $(function() {
    $('#save').click(function() {
      $.ajax({
        type: "POST",
        url: $("#AddEmail").attr('action'),
        data: $("#AddEmail").serialize(),
        dataType: "text/plain",
        success: function(response) {
          $("#details").html(response);
        }
      });
    });
  });
</script>

<% using(Html.BeginForm("Add", "Email", FormMethod.Post, new { id = "AddEmail" })) {%>
<table class="table">
<tr>
  <td>Email:</td>
  <td><%= Html.TextBox("Email")%></td>
</tr>
<tr>
  <td>Type:</td>
  <td><%= Html.DropDownList("Type") %></td>
</tr>
<tr>
  <td><%= Html.Hidden("ContactPersonId") %></td>
  <td><input type="button" name="save" id="save" value="Save" /></td>
</tr>
</table>
<% } %>

上面jQuery代码负责通过Ajax提交form.jQuery给html button(而不是input type=”submit”)附加事件,然后将页面中的内容序列化并通过post 请求发送到使用合适AcceptVerbs标签修饰的名为add()的action.

编辑和删除EmailAddress对象

编辑EmailAddress对象所涉及的action和前面提到的很相似,仍然是两个action,一个用于处理get请求,另一个用于处理post请 求:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Edit(int id)
{
  var emailAddress = EmailAddressManager.GetItem(id);
  var contactTypes = Enum.GetValues(typeof(ContactType))
    .Cast<ContactType>()
    .Select(c => new
    {
      Id = c,
      Name = c.ToString()
    });
  var model = new EmailAddressViewModel
  {
    Type = new SelectList(contactTypes, "ID", "Name", emailAddress.Type),
    Email = emailAddress.Email,
    ContactPersonId = emailAddress.ContactPersonId,
    Id = emailAddress.Id
  };
  return View(model);
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(EmailAddress emailAddress)
{
  EmailAddressManager.Save(emailAddress);
  return RedirectToAction("List", "Email", new { id = emailAddress.ContactPersonId });
}

下面的partial View代码现在应该很熟悉了吧:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<EmailAddressViewModel>" %>

<script type="text/javascript">
  $(function() {
    $('#save').click(function() {
      $.ajax({
        type: "POST",
        url: $("#EditEmail").attr('action'),
        data: $("#EditEmail").serialize(),
        dataType: "text/plain",
        success: function(response) {
          $("#details").html(response);
        }
      });
    });
  });
</script>

<% using(Html.BeginForm("Edit", "Email", FormMethod.Post, new { id = "EditEmail" })) {%>
<table class="table">
<tr>
  <td>Email:</td>
  <td><%= Html.TextBox("Email")%></td>
</tr>
<tr>
  <td>Type:</td>
  <td><%= Html.DropDownList("Type") %></td>
</tr>
<tr>
  <td><%= Html.Hidden("ContactPersonId") %><%= Html.Hidden("Id") %></td>
  <td><input type="button" name="save" id="save" value="Save" /></td>
</tr>
</table>

上面代码仍然和Add View很像,除了包含EmailAddress.Id的html隐藏域,这是为了保证正确的email地址被更新,而Delete action就不用过多解释了吧。

public ActionResult Delete(int id)
{
  EmailAddressManager.Delete(id);
  return RedirectToAction("List", "Contact");
}

总结

这篇练习的目的是为了证明ASP.NET MVC在没有Linq To Sql和Entity framework的情况下依然可以很完美的使用。文章使用了现有分层结构良好的Asp.net 2.0 form程序,还有可重用的,business Objects层,bussiness logic层以及Data Access 层。而DAL层使用Ado.net调用Sql Server的存储过程来实现。

顺带的,我还展示了如何使用强类型的View Models和简洁的jQuery来让UI体验更上一层。这个程序并不是完美的,也不是用于真实世界。程序中View部分,以及混合编辑和删除的 action都还有很大的空间可以重构提升,程序还缺少验证用户输入的手段,所有的删除操作都会返回页面本身。而更好的情况应该是显示删除后用一个子表来 显示删除后的内容,这需要将ContactPersonId作为参数传递到相关action,这也是很好实现的。

—————————————————

原文链接:http://www.mikesdotnetting.com/Article/132/ASP.NET-MVC-is-not-all-about-Linq-to-SQL

translated by CareySon

[转载]LECCO SQL Expert工具之优化sql语句

mikel阅读(1229)

[转载]LECCO SQL Expert工具之优化sql语句

程序开发,特别是web开发,对性能的要求比较高,在线列表信息要快又要占用减少服务器资源,在大众化的网络中可以已较快的速度读取数 据,在程序方面优 化,主要只书写代 码质量,这里对代 码优化不进行讨论,此 篇主是针对数据库查询语句的优化.

编程开手或DBA通过自己的多年的经验可能重写性能低下 的SQL语句,但对于我这样菜鸟来说,写出高性能的SQL有些困难.…,不用怕,我现在介绍个工具, LECCO SQL Expert,这 个工具的下载及使用帮助让大家baidu,就有一大堆.这里不提供下载链接了.

好了,开始我们今天的话题:

1.打开软件,登录后,出现以下界面.

找到我要进行测试的sql语句,如下:

SELECT dbo.合同申请表.ID,

dbo.合同申请表.ApplyUser,

dbo.UserTable.UserName,

dbo.合同申请表.ApplyType,

dbo.合同申请表.Name,

dbo.合同申请表.Object,

dbo.合同申请表.Intention,

dbo.合同申请表.Delivery,

dbo.合同申请表.Howmuch,

dbo.合同申请表.Payment,

dbo.合同申请表.Transit,

dbo.合同申请表.Others,

dbo.合同申请表.Memo,

dbo.合同申请表.Status,

dbo.合同状态表.title AS StatusTitle,

dbo.合同申请表.Attime,

dbo.UserTable.Phone,

dbo.合同申请表.Serial

FROM dbo.合同申请表,

dbo.UserTable,

dbo.合同状态表

WHERE dbo.合同申请表.status = @nStatus

and dbo.合同申请表.ApplyType = @cType

and dbo.合同申请表.WorkerID = @nOfficer

AND dbo.合同申请表.Status = dbo.合同状态表.id

AND dbo.合同申请表.ApplyUser = dbo.UserTable.ID

2.将其copyLECCO SQL Expert sql编辑器中,如图:


3.
点击工具栏的优化按钮,输入参数(sql语句用的是变量@nStatus, @cType, @nOfficer),如图:

4.输入相应的变量值,点击确定,进行优化语句查询:如图:



找到5个可选的执 行计划.,批运行 这5sql,看运行时间最短的,其是最好的优化sql

5.批运行,并显示这5个运行时间

结果显示:sql4是最优的,其语句为:

SELECT dbo.合同申请表.ID,

dbo. 合同申请表.ApplyUser,

dbo.UserTable.UserName,

dbo. 合同申请表.ApplyType,

dbo. 合同申请表.Name,

dbo. 合同申请表.Object,

dbo. 合同申请表.Intention,

dbo. 合同申请表.Delivery,

dbo. 合同申请表.Howmuch,

dbo. 合同申请表.Payment,

dbo. 合同申请表.Transit,

dbo. 合同申请表.Others,

dbo. 合同申请表.Memo,

dbo. 合同申请表.Status,

dbo. 合同状态表.title AS StatusTitle,

dbo. 合同申请表.Attime,

dbo.UserTable.Phone,

dbo. 合同申请表.Serial

FROM dbo.合同申请表

INNER JOIN dbo.合同状态表

ON dbo.合同申请表.Status = dbo.合同状态表.id

INNER JOIN dbo.UserTable

ON dbo.合同申请表.ApplyUser = dbo.UserTable.ID

WHERE dbo.合同申请表.status = @nStatus

and dbo.合同申请表.ApplyType = @cType

and dbo.合同申请表.WorkerID = @nOfficer

OPTION (FORCE ORDER)

好了,本篇只是对LECCO SQL Expert软件进行简 单应用实例说明.ok,这次就到这了.

[转载]LECCO SQL Expert Pro for SQL Server提供下载

mikel阅读(1194)

[转载]LECCO SQL Expert Pro for SQL Server提供下载

写出专家级的SQL语句

LECCO SQL Expert的出现,使SQL的优化变得极其简单,只要能够写出SQL语句,它就能帮用户找到最好性能的写法。LECCO SQL Expert不仅能在很短的时间内找到所有可能的优化方案,而且能够通过实际测试,确定最有效的优化方案。同以往的数据库优化手段相比较,LECCO SQL Expert将数据库优化技术带到了一个崭新的技术高度,依赖人的经验、耗费大量时间、受人的思维束缚的数据库优化手段已经被高效、省时且准确的自动优化 软件所取代了。通过内建的“LECCO小助手”的帮助,即使是SQL的开发新手,也能快速且简单地写出专家级的SQL语句。
下载

[转载]企业定制软件开发的两个核心问题 - TAOWEN的一些个人记录 - 博客园

mikel阅读(1430)

[转载]企业定制软件开发的两个核心问题 – TAOWEN的一些个人记录 – 博客园.

企业定制软件开发不是计算机科学,需要解决的不是编译原理也不是组合数学。那么,企业定制软件开发的核心问题是什么?

越来越感觉到,从事一个领域不需要有特别深刻的理解,但起码要知道做这个领域的事情,需要解决的核心问题是什么。比如说,开发C/S结构软件,状态 同步(C/S状态同步以及窗口之间的状态同步)就是核心问题之一,而开发B/S结构的软件,状态同步就不是那么核心的问题。如果事先知道需要有这些核心问 题需要考虑,在日常应对接踵而来的具体的事务的时候,就能够把解决问题的层次抬到更宏观的层面。

目前而言,个人感觉企业定制软件开发的核心问题有两个:

1、如何保证所有参与者(包括客户在内的开发团队,以及最终用户)的沟通强度,使其能够满足完成开发目标的需要

2、如何管理企业定制带来的软件自身内在的高复杂度,使得复杂度不会超过团队的维护能力范围

在前面一篇介绍组 织的Blog中,谈到了核心问题中的第一个,沟通强度问题。团队而言,刨去个人能力,最重要的就是人与人之间的沟通。没有好的沟通,即便团队的个 体能力都超级强,也无法形成合力。但只要有好的沟通,至少可以做到人尽其用。假设一个标准人的生产力是1/day。某些特别强的人可以达到3/day。但 是如果需要达到10/day的生产力才能在市场允许的时间下完成项目,那么就无法用一个人来完成之间事情,所以才会有团队存在的必要。但是有两个标准人, 并不会达到1+1=2/day的生产力。可能只有1.5。有三个标准人,更加不会达到1+1+1=3/day的生产力,很有可能有1.8。那么是什么制约 了团队的整体生产力,那就是沟通。当两个相关联的任务A和B是一个人做的时候,关于任务A的知识存在于左脑,关于任务B的知识存在于右脑。那么结合两个任 务的知识把其组装起来的沟通效率就是大脑内部的电信号的速度。但是如何任务A是由Dev甲完成的,任务B是由Dev乙完成的,那么整合两个任务的效率就受 到人嘴皮的震动频率的约束,受到表达能力的约束,受到理解能力的约束。有人研究过,两个人即便是面对面,传输的比特率也要低于最早的拨号式Modem。更 不用说,有的时候开发团队是分布式的。在无法看到表情,肢体语言,无法共享白板,只能在越洋电话里听到声音,而且其中还有一方是非工作时间,在这种情况 下,1+1几乎很难达到1/day的生产力。什么是高效的团队,就是能够让1+1的值尽可能大的团队。如何变得高效,让沟通变得更加高效。怎么样让沟通变 得高效高强度?这就是我们要处理的核心问题。

第一个问题可以应用于所有的人的团队行为之中。人只要聚集成群,就会有沟通问题。所谓,有人的地方就有江湖。第二个问题则特定于企业定制软件开发。 对于互联应用开发,也许复杂度的管理是其次的,最需要关注的是大用户量下的可扩展性。但是对于企业定制软件开发,由于业务自身的复杂度,导致了定制软件的 复杂度。特别是业务的组合,导致的组合复杂性。假设在理想情况下,一个系统可以分解为模块A,B,C,其复杂度都是2。在复杂度管理良好的情况下 ,这些模块是被明确划分的,要理解A,只需要关注A,以及B与C少量与A交互的部分,也许理解的复杂度只是2 + 0.5.。但是在复杂度没有管理的情况下,所有的“逻辑”(也就是复杂度)都是随意地放置的。那么也就是没法办法保证,读A的逻辑只需要关注A,甚至这个 A都是不存在的,你看到的知识一个系统,包含了A,B,C的功能,是完整的一块。这个时候要真正了解这个系统行为,可能就需要2 * 2 * 2 = 8这么高的代价了。随着模块(变量,方法,类,包,模块,Bundle)的增加,我们需要同时理解的东西也在不断增加。不去可以地管理复杂度,很有可能, 我们需要了解一块功能,就需要把所有的代码都去阅读一遍。或者说,改动了一个方法,使得整个项目都需要重新被测试,因为没有地方是可以被信任的。如何管理 复杂度?这就是我们要处理的核心问题。

有意思的事情是,这两个核心问题是重叠的。把人,角色等同于类,接口,都抽象地看成点。把沟通理解为人与人之间的联系问题。把复杂度也理解为类与类 的依赖问题。那么沟通问题和复杂度的管理问题都是如何把这些点联上线,组成一个高效的图的问题。这个图,就是一张关于“依赖”的图。人与人之间的依赖,类 与类之间的依赖,包与包之间的依赖。依赖的另外的一个名字就是Coupling。而我们追求的就是Cohesion。Coupling(耦合)/ Cohesion(内聚)这两个词的妙处在于,明白的人根据自己的经验,一看就点头。不明白的人,由于没有对应的经验,无论怎么解释,都是摸不着头脑。正 是因为其“妙不可言”性,所以我可以说这两个词就是所有问题的答案(你也无法反驳)。但至少我们可以知道企业定制软件开发的核心问题其实就是一个:就是管 理好人与人之间的Dependency,包与包之间的Dependency,使得信息可以在高度依赖的人与人之间快速传递(强调Coupling带来的消 息传递的效率),而理解又可以局限在高度内聚的模块内部(强调Cohesion带来的维护便利),但同时又不能让某人过度被依赖倒置工作过劳死了,被依赖 得越多要求其体能越好,对于包的内聚也一样,高内聚做到极致就是最小的编译单元(类?),又会导致包的粒度过小,使得包的数量变得巨大,失去了维护的便利 性。我们需要做的,就是在To Depend or Not To Depend中,根据场景作出取舍。

那么抽象而言,无论是解决沟通问题还是复杂度问题都可以归纳为:

1、设置目标指标

2、度量现有的指标,观测现有的依赖图

3、做出依赖图的调整计划,并执行

4、观察指标的变化

5、重复步骤3,4,直到目标达到

但是问题是:

1、如何度量指标?沟通的效率?代码的质量?都很能度量。

2、如何观测现有的依赖图?包的依赖还可以观测,但是团队的协作是比较难观测的。

3、如何对依赖图做调整?重构?Change Agent?人不比代码那么容易改变。

4、如果指标不是简单数字,怎么比较?怎么知道指标是朝着目标发生变化?

这四个问题,几乎没有硬的科学问题。管理复杂系统的复杂度,可能是一门硬的科学。但是夹杂了人的因素的企业定制软件开发,一定不是一门硬的科学。那 么,数学公式不是这些问题的答案。那么该朝哪个方向努力?

TO BE CONTINUED

[原创]SWFUpload能上传视频不能提交表单的问题解决办法

mikel阅读(1306)

最近在做模板时候发现,原来能用的swfupload上传视频的功能,现在不能用了?!但是视频文件上传完成后不能提交表单信息,总是提示:“Error submit form”

开始以为是代码调用的问题,去除了不必要的js代码,问题依然存在!swfupload上传的流程可以通过调用代码分析出来,代码如下:
……..

upload_progress_handler: uploadProgress, //上传进度显示处理函数uploadProgress
upload_error_handler: uploadError,//上传错误处理函数uploadError
upload_success_handler: uploadSuccess,//上传成功处理函数uploadSuccess
upload_complete_handler: uploadComplete,//上传完成处理函数uploadComplete 问题应该就出在这个函数中
………..

于是打开handler.js中查看uploadComplete的代码如下:

function uploadComplete(file) {
try {
if (this.customSettings.upload_successful) {

this.setButtonDisabled(true);
uploadDone(); //这个就是完成上传文件后的处理函数了
} else {
file.id = “singlefile”;
var progress = new FileProgress(file, this.customSettings.progress_target);
progress.setError();
progress.setStatus(“File rejected”);
progress.toggleCancel(false);

var txtFileName = document.getElementById(“txtFileName”);
txtFileName.value = “”;
//validateForm();

alert(“There was a problem with the upload.\nThe server did not accept it.”);
}
} catch (e) {
}
}

继续查看uploadDone()函数的代码,代码如下:

// Called by the queue complete handler to submit the form
function uploadDone() {
try {

document.forms[1].submit();//罪魁祸首在此

居然遍历取当前页面的forms的第二个进行提交,不管是不是要提交的表单都提交

没有找到时候就提示:Error submitting form

}

catch (ex) {
alert(“Error submitting form”);
}
}

问题找到了于是准备进行如下修改:

1.swfupload引用时的customSettings设置上传文件完成后要提交的form的Id:upload_form

2.修改uploadComplete中读取customSettings设置的upload_form,传递给uploadDone()函数

3.修改uploadDone函数加入参数id,用于传递要提交的表单的ID进行提交操作。

具体代码如下:

1.设置代码

custom_settings : {
progress_target : “fsUploadProgress”,
upload_successful : false,
upload_form:”Upload”
},

2.uploadComplete()

if (this.customSettings.upload_successful) {

this.setButtonDisabled(true);
uploadDone(this.customSettings.upload_form);
} else {

3.uploadDone()

function uploadDone(id) {
try {

document.getElementById(id).submit();
}

catch (ex) {
alert(“Error submitting form”);
}
}

[C#]Dispose模式

mikel阅读(2027)

本文讲解的是你在建立包含内存以外资源的类型,特别是处置非内存资源的时候,如何编写自己的资源管理代码。
我们已经知道了处置那些占用非受控(unmanaged)资源的对象的重要性,现在应该编写资源管理代码来处置那些包含非内存资源的类型了。整 个.NET框架组件都使用一个标准的模式来处理非内存资源。使用你建立的类型的用户也希望你遵循这个标准的模式。标准的处理模式的思想是这样的:当客户端 记得的时候使用IDisposable接口释放你的非受控资源,当客户端忘记的时候防护性地使用终结器(finalizer)。它与垃圾收集器 (Garbage Collector)一起工作,确保只在必要的时候该对象才受到与终结器相关的性能影响。这是处理非受控资源的一条很好的途径,因此我 们应该彻底地认识它。
类层次体系中的根基类(root base class)必须实现IDisposable接口以释放资源。这个类型还必须添加一个作为防御机制的终结 器。所有这些程序都把释放资源的工作委托给一个虚拟的方法,衍生的类可以根据自己的资源管理需求来重载该方法。只要衍生的类必须释放自己的资源,并且它必 须调用该函数的基类版本的时候,它才需要重载这个虚拟方法。
开始的时候,如果你的类使用了非内存资源,它就必须含有一个终结器。你不能依赖客户端总是调用Dispose()方法。因为当它们忘记这样做的时候, 你就面临资源泄漏的问题。没有调用Dispose是它们的问题,但是你却有过失。用于保证非内存资源被正确地释放的唯一途径是建立终结器。
当垃圾收集器运行的时候,它立即从内存中删除所有不带终结器的垃圾对象。所有带有终结器的对象仍然存在于内存中。这些对象都被添加到终结队列,垃圾收 集器引发一个新线程,周期性地在这些对象上运行终结器。在这些终结程序线程完成自己的工作之后,就可以从内存中删除垃圾对象了。需要终结的对象在内存中停 留的时间比没有终结器的对象停留的时间长很多。但是你别无选择。如果要使程序有防护性,在类型包含非受控资源的时候,你必须编写一个终结器。但是也不用担 心性能问题。下一步确保了客户端避免与终结相关的性能开销。
实现IDisposable接口是一种标准的途径,它通知用户和运行时系统持有资源的对象必须及时地释放。IDisposable接口仅仅包含一个方法:
public interface IDisposable
{
void Dispose( );
}
你对IDisposable.Dispose()方法的实现(implementation)负责下面四个事务:
1、释放所有的非受控资源。
2、释放所有的受控资源(包括未解开事件)。
3、设置标志表明该对象已经被处理过了。你必须在自己的公共方法中检查这种状态标志并抛出ObjectDisposed异常(如果某个对象被处理过之后再次被调用的话)。
4、禁止终结操作(finalization)。你调用GC.SuppressFinalize(this)来完成这种事务。
通过实现IDisposable接口你完成了两个事务:你为客户端及时地释放自己持有的所有受控资源提供了机制;你为客户端提供了一种释放非受控资源 的标准途径。这是一个很大的进步。当你在类型中实现了Idisposable接口的时候,客户端可以避免终结操作的开销,你的类就成为.NET世界中的” 良民”了。
但是在你建立的这种机制中仍然存在一些问题。怎样在衍生类清理自己资源的时候同时也让基类能够清理资源?如果衍生类重载了终结操作,或者添加了自己的 IDisposable实现,那么这些方法必须调用基类,否则,基类就不能正确地进行清理操作。同样,finalize(终结操作)和Dispose参与 分担了一些相同的职责。Finalize方法和Dispose方法的代码几乎相同。而且在重载接口函数后并不像你预料的那样工作。标准的Dispose模 式中的第三个方法是一个受保护的虚拟辅助函数,它分解出这些共同的事务,并给衍生类添加一个用于释放资源的”钩子(hook)”。基类包含了核心接口的代 码。作为对Dispose()或终结操作的响应,该虚拟函数为衍生类清除资源提供了”钩子”:
protected virtual void Dispose( bool isDisposing );
这个重载的方法实现支持finalize和Dispose的必要事务,由于它是虚拟的,它为所有的衍生类提供了一个入口点。衍生类可以重载这个方法, 为清除自己的资源提供适当的实现,同时还可以调用基类版本。当isDisposing为真(true)的时候,你可以清除受控和非受控资源,当 isDisposing为假(false)的时候,你只能清除非受控资源。在这两种情况下,你都可以调用基类的Dispose(bool)方法,让它清除 自己的资源。
下面有一个简短的例子,它演示了你在实现这种模式的时候所提供的代码框架。MyResourceHog类演示了实现IDisposable接口、终结器的代码,并建立了一个虚拟的Dispose方法:
public class MyResourceHog : IDisposable
{
// 已经被处理过的标记
private bool _alreadyDisposed = false;
// 终结器。调用虚拟的Dispose方法
~MyResourceHog()
{
Dispose( false );
}
// IDisposable的实现
// 调用虚拟的Dispose方法。禁止Finalization(终结操作)
public void Dispose()
{
Dispose( true );
GC.SuppressFinalize( true );
}
// 虚拟的Dispose方法
protected virtual void Dispose( bool isDisposing )
{
// 不要多次处理
if ( _alreadyDisposed )
return;
if ( isDisposing )
{
// TODO: 此处释放受控资源
}
// TODO: 此处释放非受控资源。设置被处理过标记
_alreadyDisposed = true;
}
}
如果衍生类需要执行另外的清除操作,它应该实现受保护的Dispose方法:
public class DerivedResourceHog : MyResourceHog
{
// 它有自己的被处理过标记
private bool _disposed = false;
protected override void Dispose( bool isDisposing )
{
// 不要多次处理
if ( _disposed )
return;
if ( isDisposing )
{
// TODO: 此处释放受控资源
}
// TODO: 此处释放所有受控资源

// 让基类释放自己的资源。基类负责调用GC.SuppressFinalize( )
base.Dispose( isDisposing );
// 设置衍生类的被处理过标记
_disposed = true;
}
}
请注意,基类和衍生类都包含该对象的被处理过(disposed)标记。这纯粹是起保护作用。复制这个标记可以封装构成某个对象的所有类释放资源时产生的任何可能的错误。
你必须编写防护性的Dispose和finalize。对象的处理可以按任意次序进行,你可能会遇到在调用自己类型的成员对象的Dispose()方 法之前,该对象已经被处理过了。你不应该认为这是问题,因为Dispose()方法会被多次调用。如果它在已经被处理过的对象上被调用,它就不执行任何事 务。Finalizer(终结器)也有类似的规则。如果你引用的对象仍然存在于内存中,你就没有必要检查空引用(null reference)。但是,你引用的任何对象都可能被处理了,它也可能已经被终结了。
这为我带来了与处理或清除相关的任何方法的最重要的建议:你应该仅仅释放资源,在dispose方法中不要执行任何其它操作。如果你在Dispose 或finalize方法中执行其它操作,都可能给对象的生命周期带来严重的不良影响。对象在被构造的时候才”出生”,当垃圾收集器收回它们的时候才”死 亡”。当你的程序再也不能访问它们的时候,你可以认为它们处于”昏睡”状态。如果你不能到达(reach)某个对象,你就不能调用它的方法,对于所有的意 图和目的来说,它是死的。但是带有终结器的对象被宣布死亡之前还有最后一口气。终结器除了清理非受控资源之外不应该执行其它任何操作。如果某个终结器由于 什么原因使某个对象又可以到达了,那么该对象就恢复(resurrected)了。即使它是从”昏睡”状态醒来的,它也是”活着”的。下面是一个很明显的 例子:
public class BadClass
{
// 保存某个全局对象的引用
private readonly ArrayList _finalizedList;
private string _msg;
public BadClass( ArrayList badList, string msg )
{
// 缓冲该引用
_finalizedList = badList;
_msg = (string)msg.Clone();
}
~BadClass()
{
// 把该对象添加到列表中。这个对象是可到达的,不再是垃圾了。它回来了!
_finalizedList.Add( this );
}
}
当某个BadClass对象执行自己的终结器的时候,它向全局列表上添加了对自己的引用。这仅仅使自己可到达了,它活了过来!但是这样操作所带来的问 题使任何人都会感到胆怯。该对象已经被终结了,因此垃圾收集器相信不用再次调用它的终结器了。你真的需要终结一个被恢复的对象的时候,终结操作却不会发生 了。其次,你的一些资源可能不能用了。GC不会把终结器队列中的对象可以到达的任何对象从内存中移除,但是它可能已经终结了这些对象。如果是这样的话,那 些对象一定不能再次使用了。尽管BadClass的成员仍然存在于内存中,它们却像被处理过或被终结了一样。在C#语言中没有控制终结次序的途径。你不能 使这种构造工作更可靠。不要尝试!
除了学院的练习作业之外,我从来没有见到过如此明显地使用被恢复对象的代码。但是我看到有些代码有这个倾向,它们在终结器中试图执行某些实际工作,当 终结器调用的某些函数保存了对该对象的引用的时候,它就正在把对象变成活动的状态。原则上我们必须非常仔细地检查finalizer和Dispose方法 中任何代码。如果有些代码除了释放资源之外还执行了其它的操作,我们就需要再检查一次。这些操作在未来可能引起程序bug。请移除这些操作,并确保 finalizer和Dispose()方法只释放资源,不作其它任务事务。
在受控环境中,你不必为自己建立的每个类型编写终结器,你只需要为存储非受控类型,或者包含了实现IDisposable接口的成员的类型编写终结 器。即使你只需要Disposable接口,不需要finalizer,也应该同时实现整个模式。否则,你会使衍生类的标准Dispose思想的实现变得 很复杂,从而限制了衍生类的功能。请遵循前面谈到的标准的Dispose思想,这将使你、你的类的用户、从你的类型建立衍生类的用户的生活更加轻松。

[C#]构建插件式的应用程序框架

mikel阅读(1818)

转载:http://www.cnblogs.com/guanjinke/archive/2007/03/14/675109.html
构建插件式的应用程序框架(一)----开篇
构建插件式的应用程序框架(二)----订立契约
构建插件式的应用程序框架(三)----动态加载
构建插件式的应用程序框架(四)----服务容器
构建插件式的应用程序框架(五)----管理插件
构建插件式的应用程序框架(六)----通讯机制
构建插件式的应用程序框架(七)----基本服务
构建插件式的应用程序框架(八)----视图服务的简单实现