[MVC]利用Asp.net MVC处理文件的上传下载

mikel阅读(893)

如果你仅仅只有ASP.NET Web Forms背景转而学习ASP.NET MVC的,我想你的第一个经历或许是那些曾经让你的编程变得愉悦无比的服务端控件都驾鹤西去了.FileUpload就是其中一个,而这个控件的缺席给我 们带来一些小问题。这篇文章主要说如何在ASP.NET MVC中上传文件,然后如何再从服务器中把上传过的文件下载下来.

在Web Forms中,当你把一个FileUpload控件拖到设计器中,你或许没有注意到在生成的HTML中会在form标签中加入一条额外属性 enctype="multipart/form-data". 而FileUpload控件本身会生成为<input type=”file” />,在MVC的view里,有许多种方法可以做到同样效果,第一种的HTML如下:

 

<form action="/" method="post" enctype="multipart/form-data">
<input type="file" name="FileUpload1" /><br />
<input type="submit" name="Submit" id="Submit" value="Upload" />
</form>

注意form标签已经包括了enctype标签,而method属性则设为”post”,这样设置并不多于因为默认的提交时通过HTTP get方式进行的。下面这种方式,使用Html.BeginForm()扩展方法,会生成和上面同样的HTML:

 

 

<%
using (Html.BeginForm("", "home", FormMethod.Post, new {enctype="multipart/form-data"}))
{%>
<input type="file" name="FileUpload1" /><br />
<input type="submit" name="Submit" id="Submit" value="Upload" />
<% }%>

注意<input type=”file”>标签的name属性,我们在后面再讨论,上面代码会如下图:

OK,现在我们可以浏览本地文件然后通过Upload提交按钮将文件提交到服务器端,下一步就是在服务器端处理上传的文件,在使用 fileUpload控件时,你可以很轻松的通过FileUpload的hasFile方法来查看文件是否被上传。但是在ASP.NET MVC中貌似就不是这么方便了,你会和原始的HTTP更接近一些,然而,一个扩展方法可以处理这些:

public static bool HasFile(this HttpPostedFileBase file)
{
return (file != null && file.ContentLength > 0) ? true : false;
}

当你看到对应的Controller类的代码时,你会发现Request对象作为HttpRequestBase类型的一个属性存在。 HttpReuqestBase其实是HTTP请求的一个封装,暴漏了很多属性,包括Files collection(其实是HttpFileCollectionBase的集合),在集合中的每一个元素都是HttpPostedFileBase的 集合,扩展方法是用于确保上传的文件是否存在。实际上,这和FileUpload.HasFile()方法的工作原理一致。

在Controller Action中使用起来其实很容易:

public class HomeController : Controller
{
public ActionResult Index()
{
foreach (string upload in Request.Files)
{
if (!Request.Files[upload].HasFile()) continue;
string path = AppDomain.CurrentDomain.BaseDirectory + "uploads/";
string filename = Path.GetFileName(Request.Files[upload].FileName);
Request.Files[upload].SaveAs(Path.Combine(path, filename));
}
return View();
}
}

 

多文件上传

或许你已经比我更早的想到如何更好的将Request.Files作为一个集合使用。这意味着它不仅仅只能容纳一个文件,而能容纳多个,我们将上面的View改为如下:

<%
using (Html.BeginForm("", "home", FormMethod.Post, new {enctype="multipart/form-data"}))
{%>
<input type="file" name="FileUpload1" /><br />
<input type="file" name="FileUpload2" /><br />
<input type="file" name="FileUpload3" /><br />
<input type="file" name="FileUpload4" /><br />
<input type="file" name="FileUpload5" /><br />
<input type="submit" name="Submit" id="Submit" value="Upload" />
<% }%>

效果如下:

在Controller的代码中已经检查了是否所有的文件上传框中都有文件,所以即使对于多文件上传,我们也不再需要修改Controller的代 码,注意每一个<input type=”file”>都有不同的name属性,如果你需要调用其中一个,比如说,你需要引用第三个输入框只需要使 用:Request.Files["FileUpload3"].

 

存入数据库

在你冲我狂吼”关注点分离”之前,我想声明下面的代码仅仅用于作为说明功能.我将ADO.Net的代码放入Controller action中,但我们都知道,这并不好。数据访问的代码应该放在Model中某个部分的数据访问层中.但是,下面这段代码仅仅可以给大家怎样将上传的文 件存入数据库中一个更直观的印象,首先,我们需要创建一个数据表(FileTest)并创建一个表:FileStore

Create TABLE [dbo].[FileStore](
[ID] [int] IDENTITY(1,1) NOT NULL,
[FileContent] [image] NOT NULL,
[MimeType] [nvarchar](50) NOT NULL,
[FileName] [nvarchar](50) NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

FileContent域是image数据类型,用于存储以二进制数据形成的文件,而Index Action改为:

public ActionResult Index()
{
foreach (string upload in Request.Files)
{
if (!Request.Files[upload].HasFile()) continue;
string mimeType = Request.Files[upload].ContentType;
Stream fileStream = Request.Files[upload].InputStream;
string fileName = Path.GetFileName(Request.Files[upload].FileName);
int fileLength = Request.Files[upload].ContentLength;
byte[] fileData = new byte[fileLength];
fileStream.Read(fileData, 0, fileLength);
const string connect = @"Server=.\SQLExpress;Database=FileTest;Trusted_Connection=True;";
using (var conn = new SqlConnection(connect))
{
var qry = "Insert INTO FileStore (FileContent, MimeType, FileName) VALUES (@FileContent, @MimeType, @FileName)";
var cmd = new SqlCommand(qry, conn);
cmd.Parameters.AddWithValue("@FileContent", fileData);
cmd.Parameters.AddWithValue("@MimeType", mimeType);
cmd.Parameters.AddWithValue("@FileName", fileName);
conn.Open();
cmd.ExecuteNonQuery();
}
}
return View();
}

修改后的代码会以循环的方式遍历Web页面中所有的上传文件,并检查<input type=”file”>中是否已经加入文件,然后,从文件中提取出3个信息:文件名,MIME类型(文件的类型),HTTP Request中的二进制流。二进制数据被转换为byte数组,并以image数据类型存入数据库。MIME类型和文件名对于用户从数据库中提取文件来说 非常重要。

将数据库中的文件返回给用户:

你如何将文件传送给用户取决于你最开始如何存储它,如果你将文件存入数据库,你会用流的方式将文件返还给用户,如果你将文件存在硬盘中,你只需要提 供一个超链接即可,或者也可以以流的方式。每当你需要以流的方式将文件送到浏览器中,你都的使用到File()方法的重载(而不是使用我们先前一直使用的 View()方法),对于File()方法有3类返回类型:FilePathResult,FileContentResult和 FileStreamResult,第一种类型用于直接从磁盘返回文件;第二种类型用于将byte数组返回客户端;而第三种方式将已经生成并打开的流对象 的内容返回客户端。

如果你还记得的话,我们将上传的文件存入了数据库,并以byte数组的形式存入FileContent域内.而当需要提取时,它仍然会以一个 byte数组进行提取,这意味着我们使用返回FileContentResult的File()重载,如果我们想让提取的文件名更有意义,我们使用接受3 个参数的重载,三个参数是:byte数组,MIME类型,文件名:

public FileContentResult GetFile(int id)
{
SqlDataReader rdr; byte[] fileContent = null;
string mimeType = "";string fileName = "";
const string connect = @"Server=.\SQLExpress;Database=FileTest;Trusted_Connection=True;";
using (var conn = new SqlConnection(connect))
{
var qry = "Select FileContent, MimeType, FileName FROM FileStore Where ID = @ID";
var cmd = new SqlCommand(qry, conn);
cmd.Parameters.AddWithValue("@ID", id);
conn.Open();
rdr = cmd.ExecuteReader();
if (rdr.HasRows)
{
rdr.Read();
fileContent = (byte[])rdr["FileContent"];
mimeType = rdr["MimeType"].ToString();
fileName = rdr["FileName"].ToString();
}
}
return File(fileContent, mimeType, fileName);
}

在View中最简单的使用来使用这个Action只需提供一个超链接:

<a href="/GetFile/1">Click to get file</a>

如果在数据库中存储的图片是图片类型,和使用超链接不同的是,我们通过指向Controller action的一个带有src属性的<image>标签来获取:

<img src="/GetFile/1" alt="My Image" />

下面再让我们来看看使用FilePathResult(用于从硬盘提取文件)是多简单的事:

public FilePathResult GetFileFromDisk()
{
string path = AppDomain.CurrentDomain.BaseDirectory + "uploads/";
string fileName = "test.txt";
return File(path + fileName, "text/plain", "test.txt");
}

而这也可以用过超链接提取:

<a href="/GetFileFromDisk">Click to get file</a>

而最后一个选择FileStreamResult也可以从磁盘中提取文件:

public FileStreamResult StreamFileFromDisk()
{
string path = AppDomain.CurrentDomain.BaseDirectory + "uploads/";
string fileName = "test.txt";
return File(new FileStream(path + fileName, FileMode.Open), "text/plain", fileName);
}

FilePathResult和FileStreamResult的区别是什么?我们又该如何取舍呢?主要的区别是FilePathResult使 用HttpResponse.TransmitFile来将文件写入Http输出流。这个方法并不会在服务器内存中进行缓冲,所以这对于发送大文件是一个 不错的选择。他们的区别很像DataReader和DataSet的区别。于此同时, TransmitFile还有一个bug,这可能导致文件传到客户端一半就停了,甚至无法传送。而FileStreamResult在这方面就很棒了。比 如说:返回Asp.net Chart 控件在内存中生成的图表图片,而这并不需要将图片存到磁盘中.

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

原文链接:http://www.mikesdotnetting.com/Article/125/ASP.NET-MVC-Uploading-and-Downloading-Files

[Memcached]Memcached (Distributed Cache) ASP.net P

mikel阅读(919)

转载:http://www.codeproject.com/KB/aspnet/memcached_aspnet.aspx

Introduction

Currently I am working on a web-based project that will be hosted in a web farm. Among the several issues, we faced the issue of having a distributed cache. As we know the current cache in ASP.NET is an in-process cache and can't be used in a web farm. After doing some research found a few solutions on the web but at the end all of them had scalability issues. We found a few third party implementations but they were quite expensive. Then I came across memcahced implemented by Danga Interactive. This is a high performance distributed memory cache initially implemented for http://www.LiveJournal.com. The original implementation runs on *nix system. Luckily there is win32 port available at http://jehiah.cz/projects/memcached-win32/ for those who want to run it in a windows environment. For more detail on the working of Memcached, please read the following article http://www.linuxjournal.com/article/7451.

There is a C# client for memcached available and can be downloaded from the following location https://sourceforge.net/projects/memcacheddotnet/. For coding this provider, I have used the clientlib 1.1.5.

Using the code

Following is the interface for the Cached Provider.

Collapse
public abstract class CacheProvider : ProviderBase
{
// Currently returns -1 as this property is not implemented
public abstract long Count { get;}
// Returns the server names with port in the memcached cluster
public abstract string[] Servers { get;}
// Default expiration time in milli seconds
public abstract long DefaultExpireTime { get;set;}
// Adds object to the cache for the max amount of time
public abstract bool Add(string strKey, object objValue);
// Adds object to the cache for Default Expire time if bDefaultExpire
// is set to true otherwise for max amount of time
public abstract bool Add(string strKey, object objValue,bool bDefaultExpire);
// Add objects for specified about of time. Time is specified in milli seconds        
public abstract bool Add(string strKey, object objValue, long lNumofMilliSeconds);
// Return the object from memcached based on the key otherwise 
// just returns null
public abstract object Get(string strKey);
// Clears everything from the cache on all servers
public abstract bool RemoveAll();
// Removes the an object from cache
public abstract object Remove(string strKey);
// Release resources and performs clean up
public abstract void Shutdown();
// Checks if the key exists in memory
public abstract bool KeyExists(string strKey);
// Return all servers stats
public abstract Hashtable GetStats();
}

Following is how to configure Cache Provider in a web.config or app.config file

Collapse
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="cacheProvider" type="CacheProvider.CacheProviderSection, CacheProvider"
allowDefinition="MachineToApplication" restartOnExternalChanges="true"/>
</configSections>
<cacheProvider defaultProvider="MemcachedCacheProvider">
<providers>
<add name="MemcachedCacheProvider" type="CacheProvider.MemcachedCacheProvider,CacheProvider"
servers="127.0.0.1:11211" socketConnectTimeout="1000" socketTimeout="1000"/>
<!�To add more servers use comma to separate servernames and ports
eg. servers="127.0.0.1:11211,192.168.0.111:11211"
-->
</providers>
</cacheProvider>
</configuration>

Following parameters can be specified for initializing the cache provider

  • socketConnectTimeout � Timeout for Socket connection with memcached servers
  • socketTimeout � Timeout for Socket read-write operations
  • defaultExpireTime � Default expire time in milliseconds

To use Cache Provider in a project add a reference to the CacheProvider.dll and access the methods using DistCache static class. When creating keys for storing data, avoid using spaces in keys e.g. "My Key". This is an issue with C# memcached client. To close the provider gracefully please add a call to DistCache.Shutdown() in Global.asax file's Application_End event.
Update Dec 24, 2007
To report any issues and enhancements please go to the following link http://www.codeplex.com/memcachedproviders. I have started working on the Session State Provider for Memcached. I will be releasing it very soon on codeplex.com.

Update Dec 31, 2007I have released Session State Provider for memcached. Please go to the following link to download
http://www.codeplex.com/memcachedproviders

References

  1. http://www.danga.com/memcached/
  2. http://jehiah.cz/projects/memcached-win32/
  3. https://sourceforge.net/project/showfiles.php?group_id=152153
  4. Sample Project Provider by Memcached C# client 1.1.5
  5. http://www.infoq.com/news/2007/07/memcached
  6. http://msdn2.microsoft.com/en-US/library/aa479038.aspx
  7. http://www.linuxjournal.com/article/7451

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0

About the Author

Fahad Azeem

Member
My name is Fahad Azeem. I am interested in distributed software development. Currently I am working for a software consulting company in Chicago which developes software in .NET platform.
My Blog: http://fahadaz.blogspot.com

Occupation: Web Developer
Location: United States United States

[ASP.NET]超级简单:ASP.NET Localization (本地化,多语言)

mikel阅读(782)

      有很多讨论ASP.NET localization(本地化,多语言)的文章,这篇文章是不会的深入讨论ASP.NET Localization (本地化,多语言)。相反,它将给你有关asp.net页面中通常使用的内容的localization的一个快速参考,这些内容包括:ASP.NET服 务端控件,html内容,SiteMap,一些其他资源。

      这篇文章包括以下内容:

      1、 如何本地化的ASP.NET服务器控件?

      2、如何本地化HTML内容?

      3、如何本地化站点地图?

      4、如何动态改变文化环境?

     如何本地化的ASP.NET服务器控件?

     ASP.NET服务器控件的localization是所有类型中最简单的一种。一旦你添加一个服务器控件到你的页面上,您可以简单地切换网页到“Design”,然后进入菜单 “Tools”->“Generate Local Resource”。

     它将会为页面上的每个asp.net服务器控件产生一段字符串资源。在这个例子中,创建一个名字为Default.aspx.resx 的文件。它包含了Default.aspx页面所有的资源的name/value对。

   切换回"Source",你将看到在你的html里面添加了如下的代码:

<asp:Button ID="Button1" runat="server" Text="Hello" 
    meta:resourcekey
="Button1Resource1" />

     然后,您可以复制/粘贴,为了创建另一个文化资源文件。例如,您可以为法国用户创建一个Default.aspx.fr.resx。 

 

     下面的截图是当Internet Explorer的语言设置为英语。

 

      通过Internet Explorer->Tools->Internet Options->Languages更改语言为法语. 

 

     下面是为法语版本的页面:

 

   如何本地化HTML内容?

    为了本地化普通的HTML内容,您可以使用<asp:Localize>控件。让我们用一个例子来解释。

    在您的网页,你有一个标题和段落。

<h1>Localization Page Header</h1>
<p>This is a demo page to show you how to do localization in ASP.NET</p>

     为了本地化,您需要给他们添加<asp:Localize>。

代码

<h1><asp:Localize ID="Header" runat="server">Localization Page Header</asp:Localize></h1>
<p><asp:Localize ID="Localize1" runat="server">This is a demo 
   page to show you how to do localization in ASP.NET
</asp:Localize></p>

 

      然后,您可以手动创建一个资源文件并添加meta:resourcekey =“HeaderResource1”到您的网页。您可以利用Visual Studio,它自动生成。切换页面到“Design”,进入菜单“Tools”->“Generate Local Resource”。

      它将为您生成以下代码和资源文件(例如:yourfile.aspx.resx)。

      下面是它更改的代码:

代码

<h1><asp:Localize ID="Header" runat="server" 
   meta:resourcekey
="HeaderResource1" 
   Text
="Localization Page Header"></asp:Localize></h1>
<p><asp:Localize ID="Localize1" runat="server" 
   meta:resourcekey
="Localize1Resource1" Text="This is a demo page to show you 
      how to do localization in ASP.NET"
></asp:Localize></p>

     在其余步骤是与如何本地化ASP.NET服务器控件相同。

   如何本地化SiteMap?

     本文将给你关于SiteMap的本地化更多的细节。

     1、通过加入enableLocalization =“true”,启用站点地图文件网站地图本地化。例如:在Web.sitemap文件。

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0"
    enableLocalization
="true">

   2、 在SiteMapNode中使用这种格式: “$resources:ClassName,KeyName,DefaultValue”,更改你要本地化的资源字符串的属性的值。

<siteMapNode url="Default.aspx" 
  title
="$resources:SiteMapLocalizations,HomePageTitle" 
  description
="$resources:SiteMapLocalizations,HomePageDescription">

    3、 添加 global resource 文件夹和文件。右键单击在解决方案资源管理器的web site 。点击“添加ASP.NET文件夹”。从子菜单点击“添App_GlobalResources文件”。这将增加一个 “App_GlobalResources文件”文件夹到根目录。

然后,添加一个资源文件,例如,SiteMapLocalizations.resx。在文件中,您将有资源字符串的 name/value 对。例如:

Name             Value
HomePageTitle    Home

 4、为每一种你需要的文化,添加资源文件。例如,您可能有一个名字为SiteMapLocalizations.fr.resx法语版的文件。下面是英文和法文的菜单屏幕截图:

 

如何编程本地化字符串?

有时您可能需要显示一个字符串,例如,在运行时错误信息。您需要编程将它本地化。下面是如何做到这一点:

1、在App_GlobalResources 文件夹下面添加一个资源文件。例如,我们能添加一个名字为“CommonResource.resx”文件和一个法语版的“CommonResource.fr.resx”。

2、有很多其他很好的方法来获取资源字符串。

你能从 ~\App_GlobalResources\MyMessages.resx 得到的资源通过:

1、产生的封装代码 :

string message = Resources.MyMessages.Hello;

 2、资源表达式

<asp:Label Text="<%$ Resources: MyMessages, Hello %>" />

3、GetGlobalResourceObject方法

string message = GetGlobalResourceObject("MyMessages""Hello");

你能从 ~\App_LocalResources\default.aspx.resx 得到的资源通过: 

1、资源表达式:

<asp:Label Text="<%$ Resources: Hello %>" />

2、meta:resourceKey :

<asp:Label meta:resourceKey="labelResourceKey" />

 3、GetLocalResourceObject方法:

string message = GetLocalResourceObject("Hello"); "

 这有个截图:

  

 如何动态改变文化?

    在示例代码中,我们增加了两个LinkButtons控件。当您点击“English”,该网页将切换到英语文化,点击 “Français”, 将切换到法国文化。为了检测的哪个LinkButtons被点击,我们使用Request.Form [“__EventTarget”]。它能实现,但可能不是最好的方式。

    我们覆盖页面InitializeCulture方法,这样就会对我们作出的选择显示正确的文化。

<asp:LinkButton ID="LanguageEnglish" Text="English" runat="server"></asp:LinkButton>
<asp:LinkButton ID="LanguageFrench" Text="Français" runat="server"></asp:LinkButton>

 

代码

protected override void InitializeCulture()
{
    
string language = Request.Form["__EventTarget"];
    
string languageId = "";
    
if (!string.IsNullOrEmpty(language))
    {
        
if (language.EndsWith("French"))
            languageId 
= "fr-FR";
        
else languageId = "en-US";
        Thread.CurrentThread.CurrentCulture 
= 
        CultureInfo.CreateSpecificCulture(languageId);
        Thread.CurrentThread.CurrentUICulture 
= new CultureInfo(languageId);
    }
    
base.InitializeCulture(); 
}

 

   除了menu之外,其它一切控件都有效。如果在网页中你有一个menu使用Sitemap,您可能需要在Page_Load事件调用 menu.DataBind()或设置的EnableViewState为false。否则,但其他内容更改为新的文化,你的menu上仍会显示以前的文 化字符串。

   当我们动态改变文化,最有可能的是我们需要将它存储在某个地方,当我们从页面到页面跳转时,这样就不会丢失。在示例应用程序,我们使用了Session。

源代码:

/Files/zhuqil/Localization.zip

原文:http://www.codeproject.com/KB/aspnet/AspNetLocalization.aspx

朱祁林

[Linq]非常简单的实现LINQ通用分页绑定方法

mikel阅读(909)

转载:http://www.cnblogs.com/ejiyuan/archive/2009/12/22/1629806.html

在LINQ中,IQueryable <T>接口和IEnumerable <T>接口都分别提供了Skip方法和Take方法,用来做分页非常合适.因此我就想用他们做一个分页控件,因为IQueryable <T> 是继承自 IEnumerable <T> 的。因此使用接口仅需要针对后者就可以了。使用的时候只需提供数据源、绑定的GridView的、每页大小即可。现在问题就出了在数据源上,要求用户提供 一个数据源类型,即IQueryable <T>接口和IEnumerable <T>接口? T是可确定类型(已知类型)的话还可以,若T是匿名类型,如 

var list = from it in de.Customers where it.City == "abc" select new { it.City, it.Country }; 

 

 list的类型只有在运行时才能得到,怎么办呢!其实很简单我,我们可以使用 “参数推导泛型类型”的方法来实现:
看下面的代码(因为重点不在这里所以 代码写的比较粗糙):

代码

public void BindBoundControl<TSource>(IEnumerable<TSource> DataSource, GridView BoundControl, int PageSize)
        {
            
//获取总记录数(这里可以使用参数传入总页数 就不必每次都执行下面方法)
            int totalRecordCount = DataSource.Count();
            
//计算总页数
            int totalPageCount = 0;
            
if (PageSize == 0)
            {
                PageSize 
= totalRecordCount;
            }
            
if (totalRecordCount % PageSize == 0)
            {
                totalPageCount 
= totalRecordCount / PageSize;
            }
            
else
            {
                totalPageCount 
= totalRecordCount / PageSize + 1;
            }
            
//从参数中获取当前页码
            int CurrentPageIndex = 1;
            
//如果从参数中获取页码不正确 设置页码为第一页
            if (!int.TryParse(HttpContext.Current.Request.QueryString["Page"], out CurrentPageIndex) || CurrentPageIndex <= 0 || CurrentPageIndex > totalPageCount)
            {
                CurrentPageIndex 
= 1;
            }
            
//绑定数据源
            BoundControl.DataSource = DataSource.Skip((CurrentPageIndex  1* PageSize).Take(PageSize);
            BoundControl.DataBind();
        }

 

        调用

 

代码

        protected void Page_Load(object sender, EventArgs e)
        {
            NorthwindEntities de 
= new NorthwindEntities();
            BindingUtils bind 
= new BindingUtils();
            
//先排序与一下再绑定
            bind.BindBoundControl<Customers>(de.Customers.OrderBy(v=>v.CustomerID), this.GridView1, 10);  
        }

 

下面我们只是需要重载一下我们的分页方法实现“参数推导泛型类型”就可以了 代码如下:

代码

        public void BindBoundControl<TSource>(IEnumerable<TSource> DataSource, TSource type, GridView BoundControl, int PageSize)
        {
            
this.BindBoundControl(DataSource, BoundControl, PageSize);
        }

 

调用

代码

        protected void Page_Load(object sender, EventArgs e)
        {
            NorthwindEntities de 
= new NorthwindEntities();
            var list 
= from it in de.Customers where it.City == "abc" select new { it.City, it.Country };
            BindingUtils bind 
= new BindingUtils();
            bind.BindBoundControl(list.OrderBy(c
=>c.City), list.FirstOrDefault(), this.GridView1, 10);  
        }

 

这个方法很简单的 只是通过 list.FirstOrDefault() 做参数 来推导 方法中 BindBoundControl<TSource> 的TSource 就可以了,当然因为每次分页时都会执行 list.FirstOrDefault() 会损失一点点的效率。

 

[C#]动软代码生成器源码下载地址

mikel阅读(1612)

动软代码生成器源码下载页面
http://www.maticsoft.com/download.aspx

动软.Net代码生成器(.Net 2.0版)源码

软件版本: 2.41
最后更新: 2009-12-22
软件大小: 13M
软件性质: 简体中文/免费软件
运行环境: .Net 2.0
下载次数: 194
软件描述:

        动软.Net代码生成器2.41版最新全部源码开放!

        转眼间,动软经历了几年的风风雨雨,得到了众多网友们的支持和厚爱。同时也结识了很多的朋友,虽然几年的update很辛苦,但有这么多朋友的支持和鼓励,也甚感欣慰。
为 感谢众多网友对该软件的支持,现在正式开放源码。希望它能带给大家和更多的朋友更大的帮助,也不枉这么多年开发动软的心血。虽然对动软有着深厚的感情,但 为了更好的发挥动软.NET代码生成器更大的社会价值,也为更多的程序员提供更大的便利性和灵活性。也当作我对同行朋友们新年的一点贺礼,希望大家在未来 的工作生活中,快乐工作,享受生活!

    本地免费下载

动软.Net代码生成插件源码

软件版本: 2.4
最后更新: 2009-7-19
软件大小: 69K
软件性质: 简体中文/免费软件
运行环境: Codematic 2.19
下载次数: 28405
软件描述:

动软.Net代码生成器2.1以上版本支持代码插件机制,支持可扩展的代码生成插件,用户可以定制自己的代码生成的插件,根据接口开发自己的代码生成方式,按用户需求进行代码生成。详见插件接口开发帮助和源码。
这里提供了几种典型的代码生成方式的组件源码供参考。
包括组件:
1.BuilderBLLComm  BLL层代码模板组件源码。
2.BuilderDALELParam  DAL层代码构造器(基于企业库方式)
3.BuilderDALParam  DAL数据访问层代码构造器(Parameter方式)
4.BuilderDALSQL  DAL数据访问层代码构造器(基于SQL方式)
5.BuilderModel  Model代码生成组件源码。
6.BuilderWeb  Web层代码生成组件源码。
7.Lib  需要引用的库。

同时希望大家把自己开发的代码生成插件在网上共享,别的网友也可使用已经开发好的插件覆盖安装目录下的插件库文件通过插件管理增加新插件。尽量避免重复开发。借此也可以让大家有个交流的机会。
全部源码下载

    本地免费下载

[C#].NET 中的对象序列化

mikel阅读(1284)

转载:http://www.cnblogs.com/wayfarer/articles/4759.html

Piet Obermeyer

Microsoft Corporation

 

2001 8

 

摘要:为什么要使用序列化?最重要的两个原因是:将对象的状态保存在存储媒体中以便可以在以后重新创建出完全相同的副本;按值将对象从一个应用程序域发送至另一个应用程序域。例如,序列化可用于在 ASP.NET 中保存会话状态,以及将对象复制到 Windows 窗体的剪贴板中。它还可用于按值将对象从一个应用程序域远程传递至另一个应用程序域。本文简要介绍了 Microsoft .NET 中使用的序列化。

 

目录

简介

持久存储

按值封送

基本序列化

选择性序列化

自定义序列化

序列化过程的步骤

版本控制

序列化规则

 

简介

序列化是指将对象实例的状态存储到存储媒体的过程。在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与原对象完全相同的副本。

 

在面向对象的环境中实现序列化机制时,必须在易用性和灵活性之间进行一些权衡。只要您对此过程有足够的控制能力,就可以使该过程在很大程度上自动进行。例如,简单的二进制序列化不能满足需要,或者,由于特定原因需要确定类中那些字段需要序列化。以下各部分将探讨 .NET 框架提供的可靠的序列化机制,并着重介绍使您可以根据需要自定义序列化过程的一些重要功能。

 

持久存储

我 们经常需要将对象的字段值保存到磁盘中,并在以后检索此数据。尽管不使用序列化也能完成这项工作,但这种方法通常很繁琐而且容易出错,并且在需要跟踪对象 的层次结构时,会变得越来越复杂。可以想象一下编写包含大量对象的大型业务应用程序的情形,程序员不得不为每一个对象编写代码,以便将字段和属性保存至磁 盘以及从磁盘还原这些字段和属性。序列化提供了轻松实现这个目标的快捷方法。

 

公共语言运行时 (CLR) 管理对象在内存中的分布,.NET 框架则通过使用反射提供自动的序列化机制。对象序列化后,类的名称、程序集以及类实例的所有数据成员均被写入存储媒体中。对象通常用成员变量来存储对其他实例的引用。类序列化后,序列化引擎将跟踪所有已序列化的引用对象,以确保同一对象不被序列化多次。.NET 框架所提供的序列化体系结构可以自动正确处理对象图表和循环引用。对对象图表的唯一要求是,由正在进行序列化的对象所引用的所有对象都必须标记为 Serializable(请参阅基本序列化)。否则,当序列化程序试图序列化未标记的对象时将会出现异常。

 

当反序列化已序列化的类时,将重新创建该类,并自动还原所有数据成员的值。

 

按值封送

对象仅在创建对象的应用程序域中有效。除非对象是从 MarshalByRefObject 派生得到或标记为 Serializable,否则,任何将对象作为参数传递或将其作为结果返回的尝试都将失败。如果对象标记为 Serializable,则该对象将被自动序列化,并从一个应用程序域传输至另一个应用程序域,然后进行反序列化,从而在第二个应用程序域中产生出该对象的一个精确副本。此过程通常称为按值封送。

 

如果对象是从 MarshalByRefObject 派生得到,则从一个应用程序域传递至另一个应用程序域的是对象引用,而不是对象本身。也可以将从 MarshalByRefObject 派生得到的对象标记为 Serializable。远程使用此对象时,负责进行序列化并已预先配置为 SurrogateSelector 的格式化程序将控制序列化过程,并用一个代理替换所有从 MarshalByRefObject 派生得到的对象。如果没有预先配置为 SurrogateSelector,序列化体系结构将遵从下面的标准序列化规则(请参阅序列化过程的步骤)。

 

基本序列化

要使一个类可序列化,最简单的方法是使用 Serializable 属性对它进行标记,如下所示:

 

[Serializable]

public class MyObject {

  public int n1 = 0;

  public int n2 = 0;

  public String str = null;

}

以下代码片段说明了如何将此类的一个实例序列化为一个文件:

 

MyObject obj = new MyObject();

obj.n1 = 1;

obj.n2 = 24;

obj.str = "一些字符串";

IFormatter formatter = new BinaryFormatter();

Stream stream = new FileStream("MyFile.bin", FileMode.Create,

FileAccess.Write, FileShare.None);

formatter.Serialize(stream, obj);

stream.Close();

本例使用二进制格式化程序进行序列化。您只需创建一个要使用的流和格式化程序的实例,然后调用格式化程序的 Serialize 方法。流和要序列化的对象实例作为参数提供给此调用。类中的所有成员变量(甚至标记为 private 的变量)都将被序列化,但这一点在本例中未明确体现出来。在这一点上,二进制序列化不同于只序列化公共字段的 XML 序列化程序。

 

将对象还原到它以前的状态也非常容易。首先,创建格式化程序和流以进行读取,然后让格式化程序对对象进行反序列化。以下代码片段说明了如何进行此操作。

 

IFormatter formatter = new BinaryFormatter();

Stream stream = new FileStream("MyFile.bin", FileMode.Open,

FileAccess.Read, FileShare.Read);

MyObject obj = (MyObject) formatter.Deserialize(fromStream);

stream.Close();

 

// 下面是证明

Console.WriteLine("n1: {0}", obj.n1);

Console.WriteLine("n2: {0}", obj.n2);

Console.WriteLine("str: {0}", obj.str);

上面所使用的 BinaryFormatter 效率很高,能生成非常紧凑的字节流。所有使用此格式化程序序列化的对象也可使用它进行反序列化,对于序列化将在 .NET 平 台上进行反序列化的对象,此格式化程序无疑是一个理想工具。需要注意的是,对对象进行反序列化时并不调用构造函数。对反序列化添加这项约束,是出于性能方 面的考虑。但是,这违反了对象编写者通常采用的一些运行时约定,因此,开发人员在将对象标记为可序列化时,应确保考虑了这一特殊约定。

 

如果要求具有可移植性,请使用 SoapFormatter。所要做的更改只是将以上代码中的格式化程序换成 SoapFormatter,而 Serialize Deserialize 调用不变。对于上面使用的示例,该格式化程序将生成以下结果。

 

<SOAP-ENV:Envelope

  xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance

  xmlns:xsd="http://www.w3.org/2001/XMLSchema"

  xmlns:SOAP- ENC=http://schemas.xmlsoap.org/soap/encoding/

  xmlns:SOAP- ENV=http://schemas.xmlsoap.org/soap/envelope/

  SOAP-ENV:encodingStyle=

  "http://schemas.microsoft.com/soap/encoding/clr/1.0

  http://schemas.xmlsoap.org/soap/encoding/"

  xmlns:a1="http://schemas.microsoft.com/clr/assem/ToFile">

 

  <SOAP-ENV:Body>

    <a1:MyObject id="ref-1">

      <n1>1</n1>

      <n2>24</n2>

      <str id="ref-3">一些字符串</str>

    </a1:MyObject>

  </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

需要注意的是,无法继承 Serializable 属性。如果从 MyObject 派生出一个新的类,则这个新的类也必须使用该属性进行标记,否则将无法序列化。例如,如果试图序列化以下类实例,将会显示一个 SerializationException,说明 MyStuff 类型未标记为可序列化。

 

public class MyStuff : MyObject

{

  public int n3;

}

使用序列化属性非常方便,但是它存在上述的一些限制。有关何时标记类以进行序列化(因为类编译后就无法再序列化),请参考有关说明(请参阅下面的序列化规则)。

 

选择性序列化

类通常包含不应被序列化的字段。例如,假设某个类用一个成员变量来存储线程 ID。当此类被反序列化时,序列化此类时所存储的 ID 对应的线程可能不再运行,所以对这个值进行序列化没有意义。可以通过使用 NonSerialized 属性标记成员变量来防止它们被序列化,如下所示:

 

[Serializable]

public class MyObject

{

  public int n1;

  [NonSerialized] public int n2;

  public String str;

}

自定义序列化

可以通过在对象上实现 ISerializable 接口来自定义序列化过程。这一功能在反序列化后成员变量的值失效时尤其有用,但是需要为变量提供值以重建对象的完整状态。要实现 ISerializable,需要实现 GetObjectData 方法以及一个特殊的构造函数,在反序列化对象时要用到此构造函数。以下代码示例说明了如何在前一部分中提到的 MyObject 类上实现 ISerializable

 

[Serializable]

public class MyObject : ISerializable

{

  public int n1;

  public int n2;

  public String str;

 

  public MyObject()

  {

  }

 

  protected MyObject(SerializationInfo info, StreamingContext context)

  {

    n1 = info.GetInt32("i");

    n2 = info.GetInt32("j");

    str = info.GetString("k");

  }

 

  public virtual void GetObjectData(SerializationInfo info,

StreamingContext context)

  {

    info.AddValue("i", n1);

    info.AddValue("j", n2);

    info.AddValue("k", str);

  }

}

在序列化过程中调用 GetObjectData 时,需要填充方法调用中提供的 SerializationInfo 对象。只需按名称/值对的形式添加将要序列化的变量。其名称可以是任何文本。只要已序列化的数据足以在反序列化过程中还原对象,便可以自由选择添加至 SerializationInfo 的成员变量。如果基对象实现了 ISerializable,则派生类应调用其基对象的 GetObjectData 方法。

 

需要强调的是,将 ISerializable 添加至某个类时,需要同时实现 GetObjectData 以及特殊的构造函数。如果缺少 GetObjectData,编译器将发出警告。但是,由于无法强制实现构造函数,所以,缺少构造函数时不会发出警告。如果在没有构造函数的情况下尝试反序列化某个类,将会出现异常。在消除潜在安全性和版本控制问题等方面,当前设计优于 SetObjectData 方法。例如,如果将 SetObjectData 方法定义为某个接口的一部分,则此方法必须是公共方法,这使得用户不得不编写代码来防止多次调用 SetObjectData 方法。可以想象,如果某个对象正在执行某些操作,而某个恶意应用程序却调用此对象的 SetObjectData 方法,将会引起一些潜在的麻烦。

 

在反序列化过程中,使用出于此目的而提供的构造函数将 SerializationInfo 传递给类。对象反序列化时,对构造函数的任何可见性约束都将被忽略,因此,可以将类标记为 publicprotectedinternal private。一个不错的办法是,在类未封装的情况下,将构造函数标记为 protect。如果类已封装,则应标记为 private。要还原对象的状态,只需使用序列化时采用的名称,从 SerializationInfo 中检索变量的值。如果基类实现了 ISerializable,则应调用基类的构造函数,以使基础对象可以还原其变量。

 

如果从实现了 ISerializable 的类派生出一个新的类,则只要新的类中含有任何需要序列化的变量,就必须同时实现构造函数以及 GetObjectData 方法。以下代码片段显示了如何使用上文所示的 MyObject 类来完成此操作。

 

[Serializable]

public class ObjectTwo : MyObject

{

  public int num;

 

  public ObjectTwo() : base()

  {

  }

 

  protected ObjectTwo(SerializationInfo si, StreamingContext context) :

base(si,context)

  {

    num = si.GetInt32("num");

  }

 

  public override void GetObjectData(SerializationInfo si,

StreamingContext context)

  {

    base.GetObjectData(si,context);

    si.AddValue("num", num);

  }

}

切记要在反序列化构造函数中调用基类,否则,将永远不会调用基类上的构造函数,并且在反序列化后也无法构建完整的对象。

 

对象被彻底重新构建,但是在反系列化过程中调用方法可能会带来不良的副作用,因为被调用的方法可能引用了在调用时尚未反序列化的对象引用。如果正在进行反序列化的类实现了 IDeserializationCallback,则反序列化整个对象图表后,将自动调用 OnSerialization 方法。此时,引用的所有子对象均已完全还原。有些类不使用上述事件侦听器,很难对它们进行反序列化,散列表便是一个典型的例子。在反序列化过程中检索关键字/值对非常容易,但是,由于无法保证从散列表派生出的类已反序列化,所以把这些对象添加回散列表时会出现一些问题。因此,建议目前不要在散列表上调用方法。

 

序列化过程的步骤

在格式化程序上调用 Serialize 方法时,对象序列化按照以下规则进行:

 

检查格式化程序是否有代理选取器。如果有,检查代理选取器是否处理指定类型的对象。如果选取器处理此对象类型,将在代理选取器上调用 ISerializable.GetObjectData

如果没有代理选取器或有却不处理此类型,将检查是否使用 Serializable 属性对对象进行标记。如果未标记,将会引发 SerializationException

如果对象已被正确标记,将检查对象是否实现了 ISerializable。如果已实现,将在对象上调用 GetObjectData

如果对象未实现 Serializable,将使用默认的序列化策略,对所有未标记为 NonSerialized 的字段都进行序列化。

版本控制

.NET 框架支持版本控制和并排执行,并且,如果类的接口保持一致,所有类均可跨版本工作。由于序列化涉及的是成员变量而非接口,所以,在向要跨版本序列化的类中添加成员变量,或从中删除变量时,应谨慎行事。特别是对于未实现 ISerializable 的类更应如此。若当前版本的状态发生了任何变化(例如添加成员变量、更改变量类型或更改变量名称),都意味着如果同一类型的现有对象是使用早期版本进行序列化的,则无法成功对它们进行反序列化。

 

如果对象的状态需要在不同版本间发生改变,类的作者可以有两种选择:

 

实现 ISerializable。这使您可以精确地控制序列化和反序列化过程,在反序列化过程中正确地添加和解释未来状态。

使用 NonSerialized 属性标记不重要的成员变量。仅当预计类在不同版本间的变化较小时,才可使用这个选项。例如,把一个新变量添加至类的较高版本后,可以将该变量标记为 NonSerialized,以确保该类与早期版本保持兼容。

序列化规则

由 于类编译后便无法序列化,所以在设计新类时应考虑序列化。需要考虑的问题有:是否必须跨应用程序域来发送此类?是否要远程使用此类?用户将如何使用此类? 也许他们会从我的类中派生出一个需要序列化的新类。只要有这种可能性,就应将类标记为可序列化。除下列情况以外,最好将所有类都标记为可序列化:

 

所有的类都永远也不会跨越应用程序域。如果某个类不要求序列化但需要跨越应用程序域,请从 MarshalByRefObject 派生此类。

类存储仅适用于其当前实例的特殊指针。例如,如果某个类包含非受控的内存或文件句柄,请确保将这些字段标记为 NonSerialized 或根本不序列化此类。

某些数据成员包含敏感信息。在这种情况下,建议实现 ISerializable 并仅序列化所要求的字段。

[MVC]分页存储过程,ASP.NET MVC中的Linq分页

mikel阅读(957)

转载:http://www.cnblogs.com/sonven/archive/2009/07/27/1531836.html
分页存储过程 


Alter procedure [dbo].[sys_getPagerData]
    
@pageSize int数据条数,注意从1开始
    @pageIndex int,页数索引
    @fields nvarchar(100),选取字段
    @Conditions nvarchar(50),选择条件
    @Chart nvarchar(50), 要选取的表
    @recordCount int output, 记录总数
    @pageCount int output 页面条数
AS
declare @SQL nvarchar(300)SQL语句
declare @SkipCount int要跳过查询的记录数

/* 获取记录总数 */
declare @getRecordSql nvarchar(100
set @getRecordSql='select @recordcount=count(1) from '+@chart
exec sp_executesql @getRecordSql,N'@recordCount int output',@recordCount output
/* 计算总页数 */
select @pagecount=floor(@recordCount/@pageSize);
if(@recordCount%@pageSize!=0)set @pagecount=@pageCount+1
/* 计算要跳过查询的数目 */
if(@pagecount=1 or @pagecount=0)set @skipCount=0
else set @skipCount=@pageSize*(@pageCount1);
set @sql='select top '+convert(nvarchar,@pageSize)+' '+
    
@fields+' from '+@Chart
+' where(id not in(select top '+
    
convert(nvarchar,(@skipCount))+' id from '+@Chart+
' order by id desc))'
/*附加查询条件*/
if(@Conditions is not null and @Conditions!='')
    
set @sql=@sql+' and '+@Conditions
添加 print @sql可以监视执行的Sql语句–

execute(@sql)

 

广告:http://www.cnyolee.com/(讲述有理的网站)
      http://www.rsion.com/

ASP.NET MVC中分页

 public ActionResult CateList(string page)
        
{
            
//分页大小
            int pageSize = 15;
            
//总页数
            int recordCount = (int)Helper.DataControl.FactoryCommand("select count(0) from articles where",CommandType.Text).ExecuteScalar();
            
int pageCount = recordCount / pageSize + (recordCount % pageSize == 0 ? 0 : 1);

            
//当前页数
            int currentPage = page == null ? 0 :Convert.ToInt32(page);
            
if (currentPage <1) currentPage = 1;
            
else if (currentPage > pageCount) currentPage = pageCount;
            
//分页信息
            TempData["pagedInfo"= "<a href=\"" + Request.Path + "?page=" + (currentPage == 1 ? 1 : currentPage – 1) +
                "\">上一页</a> | <a href=\"" + Request.Path + "?page=" + (currentPage == pageCount ? pageCount : currentPage + 1+
                
"\">下一页</a> <input type=\"text\" size=\"3\" id=\"tbpage\"> <a href=\"#\" onclick=\"location.href='" + Request.Path +
                
"?page='+tbpage.value;\">跳页</a> "+
                
                
"" + (currentPage) + "页/共" + pageCount + "页&nbsp;每页" + pageSize +
                
"条记录/共" + recordCount + "条!";

            
//计算要跳过的页
            int skipCount =recordCount<=pageSize?0:pageSize * (currentPage 1);

            IEnumerable
<Models.Article> articles = Common.DataContext.Articles.Skip(skipCount).Take(pageSize).OrderByDescending(a=>a.AddDate);
      
//注意:要先使用Skip(int)后再使用Take(int)
            return View(articles);
        }

 

[Linq]LINQ可视化查询编辑器: VLinq

mikel阅读(885)

转载:http://www.cnblogs.com/lyj/archive/2008/04/02/1135120.html

大家学习LINQ是不是寻思写LINQ to SQL语句没有一个可视化的编程环境。Mitsu和他们的团队用了近一年的工作在今天发布了VLinq(Visual Linq Query Builder,LINQ可视化查询编辑器)。

Visual Linq Query Builder(LINQ可视化查询编辑器)作为Visual Studio 2008的一个插件,可以帮助我们在程序中创建LINQ to SQL查询表达式,支持C#和VB两种语言。

Linq可视化查询编辑器

VLinq使用Visual Studio 2008 (betas then RTM) 和Expression Blend开发的。在下载页中提供了整个工程项目和一个安装文件。下载文件:

  • msi安装文件
  • 快速参考指南
  • 用户说明文件
  • 2分钟的开发视频。
  • 源代码

下面是摘自Mitsu博客中的描述的快速开发指南:

1.创建一个新程序

创建一个新程序

2.添加LINQ to SQL class

添加LINQ to SQL class

3.添加VLinq queries

添加VLinq queries

4.设置VLINQ连接

设置VLINQ连接

5.创建新的查询语句

创建新的查询语句

6.在可视化编辑器中编辑查询语句

在可视化编辑器中编辑查询语句

可以收缩和展开查询节点

可以收缩和展开查询节点

7.预览查询结果

预览查询结果

8.查看自动生成的代码

查看自动生成的代码

更多使用可以参考开发视频和快速开发指南。

注意:Visual Linq Query Builder目前好像只支持英文版,我目前电脑安装的是中文版不可以使用,没有给大家介绍详细开发实例。抱歉!大家可以去试试,分享一下!

[框架]Shuttler.Net2.0圣诞开源发布

mikel阅读(962)

转载:http://www.cnblogs.com/overred/archive/2009/12/20/Shuttler_Net_2.html

Shuttler.Net(开源)
Shuttler.Net是一个高性能分布式框架,如果你在使用老去的remoting,webservices分布式架构,或在使用新生的wcf,那么你也可以尝试下Shuttler.Net。
如果你想开发自己的IM服务端和客户端(或游戏大厅),你也可以使用Shuttler.Net,只需你制定报文协议即可,其他传输层Shuttler帮你搞定。
Shuttler.Net核心组件Artery正如她的名字一样:脉,基于Tcp的应用栈,可以帮你传输任何能量,使你想唱就唱。

主要功能点包括:
1,分布式RPC,目前支持Tcp和Http(类REST风格)双通道(见Demo:TcpRpcTest和HttpRpcTest):
可以多个RpcServer端和多个RpcClient端,其中client通过HashingAlgorithm根据Key计算出server。
2,分布式缓存系统(Memcached),包括MemcachedServer和MemcachedClient(见Demo:MemcachedTest):
可以多个MemcachedServer端和多个MemcachedClient端,其中client通过HashingAlgorithm根据Key计算出server。
3,IM协议栈,使用Shuttler.Net的Artery组件可以轻松实现一个IMServer端和IMClient端(见Demo:IMTest):
IMTest中实现IM的登录密码校验,通讯协议自己定义即可,协议Demo见Shuttler_Artery_Protocol。

其中Shuttler.Net使用内存Pool概念和Socket增强SocketAsyncEventArgs,使你的所有操作Buffer始终在一块固定的内存区中进行,避免了内存泄漏问题。
值得一提的是,里面还有一个高效的CompactHeap,使你可以在12s内把数亿条数据缓存到800MB内存中(根据sizeof大小而定),如果使用对象级的托管堆,你是难以办到的。
总之里面更精彩!

Shuttler.Net核心组件Artery和Rpc结构图:


Rpc性能计数器相关(不同机器可能有出入):

 

Shuttler.Net开源主页:

http://shuttler.codeplex.com

 

源码(含Demo)下载地址:
Shuttler.Net

 

PS:这个框架是我花了无数个周末时间打造而成!尤其是Tcp流的包完整性解析,曾尝试了无数个算法! 对性能也进行了无数次调优!尽管如此还是不尽我意,那就先这样吧,我会使她一直进化下去。

 

希望两块布子做的是花衣裳!

有问题请留言或联系:overred@gmail.com

[HTML]10个你需要了解的不常见的Html标签(译)

mikel阅读(887)

原文地址:http://net.tutsplus.com/articles/web-roundups/10-rare-html-tags-you-really-should-know/

      如今,Web开发工程师在学习和工作中通常都使用了不止一门语言。因此,对一门语言的方方面面我们很难说得上都去了解,要精通一门语言也是相当有难度,比如语言中一些生僻但可能很有用处的关键字用法。

      虽然我们以前可能对这些非常少见的HTML标签并不了解或没能完全用好他们,不过亡羊补牢,为时未晚,现在开始了解并能在以后的开发中正确的用上这些以前没用过的标签也不算太晚。

      这里我给出了10个最不常见并且常被人误用的HTML标签。虽然可能并不像其他HTML标签那么常见,但在某些特殊的情景下,他们仍然相当有用。

1. <cite>

     相信大家都对<blockquote>不陌生吧,但你知道<blockquote>其实有个小弟叫<cite> 不?<cite>允许在一个元素中定义一段文本作为引用。一般情况下,浏览器会把<cite>标签下的文本设置为斜体字,不过这 可能会根据CSS有所改变。

      <cite>标签在书籍目录和其他站点地址引用的时候非常有用。这里给出一个如何在一段文字中使用<cite>标签的例子:

       张三的突破性专著张三自传给网络带来一股新气象.

2. <optgroup>

     当你想在一个下拉框中对根据不同类型分组的选项添加一些定义时,<optiongroup>标签将会非常有用。例如,如果你想根据时间对电影进行分组,代码可以这样写:

1 <LABEL for=showtimes>Showtimes</LABEL><br><Select id=showtimes name=showtimes><OPTGROUP label=1PM></OPTGROUP> <OPTION selected value=titanic>Twister</OPTION> <OPTION value=nd>Napoleon Dynamite</OPTION><OPTION value=wab>What About Bob?</OPTION><OPTGROUP label=2PM></OPTGROUP> <OPTION value=bkrw>Be Kind Rewind</OPTION> <OPTION value=stf>Stranger Than Fiction</OPTION></Select>

例子:

3. <acronym>

     <acronym>标签通常用于对一句话(词组)添加定义或者更详细的解释。当用户将鼠标停留在添加了<acronym>标签的文字上面,添加的注释或定义会在文字下方显示。如:

1 微博网站 <ACRONYM title="Founded in 2006"> Twitter</ACRONYM> 最近引起了互联网上的一股新的风潮!

例子:

微博网站 Twitter最近引起了互联网上的一股新的风潮!

4. <address>

     <address>标签是个相当少见的标签,不过这并不代表它没什么用处。望文生义,<address>允许你在HTML中根据 语义来标记地址。这个很好用的标签同样会把它内部的数据用斜体字标识,不过,这个样式很容易通过CSS修改。

1 <address><br>中国,上海市,闵行区,XX路,XX小区,XXX室<br></address>

例子:

中国,上海市,闵行区,XX路,XX小区,XXX室

 

5. <ins> 和 <del>

     如果你想通过标记来显示文档编辑样式,<ins>和<del>刚好可以用到。就像它们的名字,<ins>通过一个下划线来突出那些被添加进文档的内容,而<del>则通过删除线来显示那些从中删除的文字。

1 没有了驴子,我们的日子还要怎么<DEL>过下去</DEL> <INS>活下去</INS>?

例子:没有了驴子,我们的日子还要怎么过下去 活下去?

6. <label>

     当标记文档时,表格元素很容易被遗忘。在表格元素中,最容易被遗忘的元素之一怕要数<label>标签了。但对<label>标 签来说,它不仅可以相当方便的表示一段文字,同时,它更能通过for属性来指定标签被用于哪个元素。这些<label>不仅很容易被定义样 式,它们还允许你将标签的文字设计成像按钮一样可以被用户点击。

1 <LABEL for="username">用户名</LABEL>  <br><INPUT id="username" type="text">

7. <fieldset>

     <fieldset>是一个相当好用的标签,它可将表单内的相关元素按逻辑分组。一旦这些元素通过<fieldset>标签放到一起,另外通过将<label>标签和fieldset绑定可以为分组定义标题。

1 <FORM><FIELDSET>  <br><LEGEND>你觉得自己牛X么?</LEGEND>  <br>Yes<INPUT value=yes type=radio name=yes>  <br>No <INPUT value=no type=radio name=no>  <br></FIELDSET>  <br></FORM>

例子:

你觉得自己牛X么?

Yes No

8. <abbr>

     <abbr>和<acronym>是一类的标签,只是<abbr>标签只用于定义缩写的词组。就 像<acronym>,相当于你给元素添加了一个标题或称号。当用户将鼠标悬停在缩写词上面,它的全称会在下方显 示。<abbr>标签很少被用到,不过它对屏幕阅读器,拼写检查程序和搜索引擎很有用。

1 他<ABBR title="妈">文明用语</ABBR>的

例子:文明用语的!

9. rel

    Rel是一个相当有用的属性,基本上任何一个HTML元素都可以应用Rel属性(注1)。它可以为那些没有别的方式提供详细信息的元素提供额外的信息。这 在JavaScript和HTML一起工作时尤其有用。如果你有一个你可能想在内部编辑,你可以这样添加代码:

 

代码

<html> <body> <p><a id="myAnchor" rel="index" href="http://www.w3school.com.cn">Visit W3School.com.cn</a></p> <script type="text/javascript"> x=document.getElementById("myAnchor"); document.write(x.rel); </script> </body> </html>

 

     JavaScript会找到rel属性为clickable的link元素,然后它可以接着通过ajax内部改变元素。当然,这个只是你可以应用rel属性的无数种情况中的一种,你可以用其他方式来很好的使用rel属性。

10. <wbr>

     <wbr>(注2)是个基本已经销声匿迹的标签。坦诚的说,我怀疑读者中的大多数都没接触过这个标签,毕竟它太少用到了(真的,在写这篇文章 之前,我自己都没见过这个标签)。这个标签允许你指定一块区域来强制使用换行符,但仅仅是确实必要的时候。该元素很特殊因为它定义在浏览器中添加换行符, 如果需要的话,它可以在你极力避免浏览器中出现横向的滚动条时实现符合要求的界面。

如果你想在不必使用<wbr>标签的情况下达到相同的效果,你也可以尝试&#8203;或&shy; 。但千万注意,这三个标签中没有一个可以完全支持所有浏览器的。如果你想看看哪些浏览器支持这三种标签可以看看这篇文章

 

译者注:

注1,实际上rel通常用在a和link标签中,它常和rev一起出现。

注2,wbr不是标准的html标签,它最开始是网景公司添加的,但随后被移除掉了。

 

附注:

      这篇文章仅仅是一个参考,实际上,由于一些地方使用和解释得并不清楚, 它也引起了比较多的争论,建议如果确实对这些标签有兴趣研究的朋友,可以参看下原文地址并仔细的查看文章的一些回复。

      另外有朋友认为这些少见的标签兼容性会很差,所以我们应少用。然而恰恰相反,上面列举的标签,除了最后一个不符合标准不推荐使用之外,其他都符合W3C标 准,它们兼容目前任何主流浏览器。当然,由于<acronym>和<abbr>功能基本一样,在新的html 5标准中不推荐使用<acronym>,w3c推荐用<abbr>代替<acronym>。

       最后有人可能认为这里的一些标签都可以用其他一些常见标签实现相同功能,因此没必要使用。不过正如回复中沉默杨仔所说:“w3c就是要语义化页面内容”,对用户说,可能你可以通过普通标签实现一样的功能,但对机器(e.g.屏幕阅读器,单词拼写检查程序,搜索引擎等)来说,这种标签它们更容易懂。所以我认为,如果你的网页中真有这些标签可以应用的场合,最好还是使用这些标签来实现相应的功能。

 

Always There, Always Ready!