一、前因
因为项目中需要在silverlight 中导出Excel文件,所以就在琢磨这个事情了,开始时候的想法是能不能通过js 导出excel,在网上查了资料,试了所有找到的方法,可惜没有一个成功的。想不出其他办法,只能绕着走了,可能有点蠢,呵呵。不知道大家是怎么解决的,我把自己的发出来,抛砖引玉,不恰当的地方欢迎指出。
二、具体实现
整个解决方案包括以下几个项目,如图:
其中的BLL,Enity项目只是提供一个示例,没多大用处。ExcelExport项目中的SearchParam.cs文件中包含查询参数类,以及导航处理类。导航处理类主要是根据传入的参数集合、导出类型生成查询字符串,并传给Export.ashx处理。代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// 查询参数类
/// </summary>
public class SearchParam
{
public string Value { get; set; }
public object Name { get; set; }
public SearchParam(string value, string name)
{
Value = value;
Name = name;
}
public override string ToString()
{
return Value + "_" + Name;
}
}
/// <summary>
/// 导出处理
/// </summary>
public class ExportHandle
{
/// <summary>
/// 获取查询字符串
/// </summary>
/// <param name="searchParams">参数集合</param>
/// <returns></returns>
private static string GetQueryString(IEnumerable<SearchParam> searchParams)
{
StringBuilder builder = new StringBuilder("condition=");
foreach (var param in searchParams)
{
builder.Append(param.ToString() + " ");
}
return builder.ToString().TrimEnd();
}
/// <summary>
/// 导出处理
/// </summary>
/// <param name="paramCollection">参数集合</param>
/// <param name="action">导出类型</param>
public static void Action(SearchParam[] paramCollection, string action)
{
string paramString = GetQueryString(paramCollection);
var uriInfo = HtmlPage.Document.DocumentUri;
var path = uriInfo.AbsoluteUri.Replace(uriInfo.AbsolutePath, "");
string uriString = string.Concat(path, "/Export.ashx?", "action=", action, "&", paramString);
HtmlPage.Window.Navigate(new System.Uri(uriString, UriKind.Absolute));
}
}
在项目ExcelExport.Web中增加了一个导出处理,用来将传入的参数进行处理,并发送到WCF服务获取导出信息,然后以excel格式返回。其中存在一个正则表达式处理类,用来对查询字符串处理返回查询参数集合。代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// $codebehindclassname$ 的摘要说明
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Export : IHttpHandler
{
#region IHttpHandler接口
public void ProcessRequest(HttpContext context)
{
var queryString = context.Request.QueryString;
string action = queryString["action"];
string condition = queryString["condition"];
var searchParams = GetParams(condition);
ExportClient client = new ExportClient("WSHttpBinding_IExport");
string content=client.GetExportString(searchParams, action);
ExportToExcel(context.Response, content,action);
}
public bool IsReusable
{
get
{
return true;
}
}
#endregion
#region
private SearchParam[] GetParams(string condition)
{
string pattern = @"\b(\S+)_(\S+)\b";
IRegular regular = new Regular();
RegularInfo info = new RegularInfo(condition, pattern, RegexOptions.IgnoreCase);
var matchs = regular.Filter(info);
SearchParam[] searchParams=new SearchParam[matchs.Length];
int i = 0; SearchParam param;
foreach (Match match in matchs)
{
param = new SearchParam();
param.Name = match.Groups[1].Value;
param.Value = match.Groups[2].Value;
searchParams[i] = param;
i++;
}
return searchParams;
}
protected void ExportToExcel(HttpResponse response,string content,string action)
{
response.Clear();
response.Buffer = true;
response.Charset = "GB2312";
//page.Response.Charset = "UTF-8";
response.AppendHeader("Content-Disposition", "attachment;filename=" + action + ".xls");
response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312");//设置输出流为简体中文
response.ContentType = "application/ms-excel";//设置输出文件类型为excel文件。
response.Write(content);
response.End();
}
#endregion
}
正则表达式处理代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
{
Match[] Filter(RegularInfo info);
}
/// <summary>
/// 正则表达式处理
/// </summary>
public class Regular:IRegular
{
#region IRegular 成员
public Match[] Filter(RegularInfo info)
{
var matchCollection = Regex.Matches(info.Source, info.Pattern, info.Options);
Match[] result = new Match[matchCollection.Count];
int i = 0;
foreach (Match match in matchCollection)
{
result[i] = match;
i++;
}
return result;
}
#endregion
}
/// <summary>
/// 正则表达式信息
/// </summary>
public class RegularInfo
{
public string Source { get; set; }
public string Pattern { get; set; }
public RegexOptions Options { get; set; }
public RegularInfo(string source, string pattern, RegexOptions options)
{
Source = source;
Pattern = pattern;
Options = options;
}
}
项目ExportConfig中包括的内容是最重要的,主要分为接口、默认实现、导出处理、查询实体类四部分。接口分别为(1)IExportContent存在两个方法,Print()用来返回一行中各列的值,GetFormat() 返回单元格的样式,这里的样式必须为css样式;(2)IContentIterator内容迭代接口;(3)IExportFactory存在CreateHead,CreateContent两个方法,分别用来返回表头,表内容迭代。默认实现为:ExportContent,ContentAggregate,ContentIterator,ExportAbstractFactory。导出处理放在ExportHandle类。
接口代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// 内容迭代接口
/// </summary>
public interface IContentIterator
{
bool HasNext();
IExportContent Next();
}
/// <summary>
/// 内容接口
/// </summary>
public interface IExportContent
{
string[] Print();
string GetFormat();
}
/// <summary>
/// 表信息工厂接口
/// </summary>
public interface IExportFactory
{
IExportContent CreateHead();
IContentIterator CreateContent(SearchCollection condition);
}
导出处理类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
{
private IExportFactory factory;
public ExportHandle(IExportFactory factory)
{
this.factory = factory;
}
public string GetExportString(SearchCollection condition)
{
var head = factory.CreateHead();
StringBuilder build = new StringBuilder("<table>");
AppandString(head, build);
var iterator = factory.CreateContent(condition);
IExportContent item;
while (iterator.HasNext())
{
item = iterator.Next();
AppandString(item, build);
}
build.Append("</table>");
return build.ToString();
}
private void AppandString(IExportContent item,StringBuilder build)
{
string format = item.GetFormat(), value;
bool hasFormat = !string.IsNullOrEmpty(format);
build.Append("<tr>");
var stringList = item.Print();
foreach (var str in stringList)
{
if (hasFormat)
{
value = string.Format("<td style=\"border-color:Gray; border-thin;border-style:ridge;{0}\">{1}</td>", format, str);
}
else
{
value = string.Format("<td style=\"border-color:Gray; border-thin;border-style:ridge\">{0}</td>", str);
}
build.Append(value);
}
build.Append("</tr>");
}
}
最后一个项目ExportService 是用来提供WCF服务的,这里还存在一个设置,可以在web.config中添加导出的类名,以及程序集名称 ,如图:
获取配置信息后,通过反射创建实例。然后将查询参数、实例传给导出处理类进行操作。如下代码所示:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
[ServiceBehavior]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Export : IExport
{
#region IExport 成员
public string GetExportString(SearchParam[] paramCollection, string action)
{
string[] infos = ConfigurationSettings.AppSettings[action].Split('|');
SearchCollection condition = null;
if (paramCollection != null)
{
condition = new SearchCollection();
foreach (var param in paramCollection)
{
condition.Add(param);
}
}
IExportFactory instance = (IExportFactory)CommonHelp.CreateInstance(infos[1], infos[0], null);
ExportHandle handle = new ExportHandle(instance);
return handle.GetExportString(condition);
}
#endregion
}
public class CommonHelp
{
public static object CreateInstance(string type, string assembly, object[] args)
{
return Assembly.Load(assembly).CreateInstance(type, true, BindingFlags.Default, null, args, null, null);
}
}
另外,WCF调用可能存在跨域问题,在IIS网站根目录下放这个clientaccesspolicy.xml文件就OK了。第一次写可能有点乱,觉得还点用,就将就着看下吧,呵呵。完整的Demo下载:
/Files/WGZ_Home/ExcelExport.rar
——————————————————————————————————————————————————————————————————————————————————
经(笨笨的猪)朋友的提醒,现在把handle去掉了,并进行了一些小的修改,silverlight直接引用WCF服务,并返回byte[],然后通过SaveDialog保存。修改后的关于silverlight的
处理代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
{
ObservableCollection<SearchParam> paramCollection = new ObservableCollection<SearchParam>();
var param=new SearchParam();
param.Name="2";
param.Value="2";
paramCollection.Add(param);
SaveFileDialog dialog=new SaveFileDialog();
ExportHandle("ATPExport", paramCollection, dialog);
}
public static void ExportHandle(string action,ObservableCollection<ExeclExport.Export.SearchParam> paramCollection,SaveFileDialog dialog)
{
try
{
dialog.DefaultExt = ".txt";
dialog.Filter = "Excel Files|*.xls|Log Files|*.doc";
dialog.FilterIndex = 1;
}
catch ( Exception ex )
{
HtmlPage.Window.Alert(ex.Message);
return;
}
bool? dialogResult = dialog.ShowDialog();
if ( dialogResult == true )
{
Export.ExportClient client = new ExeclExport.Export.ExportClient();
client.GetExportStringCompleted += delegate(object sender, ExeclExport.Export.GetExportStringCompletedEventArgs e)
{
if(e.Error==null)
{
using ( Stream fs =dialog.OpenFile() )
{
var resultBytes = e.Result;
fs.Write(resultBytes, 0, resultBytes.Length);
fs.Close();
HtmlPage.Window.Alert("保存成功");
}
return;
}
client.CloseAsync();
HtmlPage.Window.Alert(e.Error.Message);
};
client.GetExportStringAsync(paramCollection, action);
}
}
完整Demo如下:/Files/WGZ_Home/ExcelExport.rar