悠闲小风专栏

SharePoint & Workflow 解决方案

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  55 随笔 :: 0 文章 :: 31 评论 :: 0 引用

2010年11月24日 #

转载自:玄魂的思想的博客 一次艰难的ASP.NET生成Excel文件的历程总结

 

统计系统的最后一项任务是导出数据到Excel,由于是第一次做,边学边搞,真费了一番周折,完成之后赶紧做了个总结。

开发环境如下:

操作系统:Windows7

开发工具:vs2010

.NET版本:4.0

服务器系统:Windows2003

office版本:2003

本文主要涉及的问题:

1) 生成Excel文件的方法

2)合并单元格与数字列标识转字母列标识

3)"异常来自 HRESULT:0x800A03EC "的原因

4)"对象为空"异常和服务器端部署

5)"80080005异常"与权限配置

一.生成Exel的方法

生成Excel的方法为调用本地Office COM组件,操作Excel。新建项目后,添加对应Office版本的Microsoft.Office.Interop.Excel的引用,如图1-1所示。

1-1 添加Microsoft.Office.Interop.Excel引用

为方便起见,这里以一个示例程序说明我的过程。示例程序整体结构如代码清单1-1所示。

代码清单1-1 示例程序结构

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Excel=Microsoft.Office.Interop.Excel;

namespace excel

{

class Program

{

private Excel.Application app = null;

private Excel.Workbook workbook = null;

private Excel.Worksheet worksheet = null;

private Excel.Range workSheet_range = null;

static void Main(string[] args)

{

}

public void createExcel()

{

}

public void addData(int row, int col, string data, string formatstring cell1string cell2)

{

}

public void export()

{

}

}

}

首先我先声明了四个字段,分别解释如下:

1)Excel.Application app。Application对象表示Excel应用程序本身。Application对象公开了大量有关正在运行的应用程序、应用于该实例的选项以及在该实例中打开的当前用户的对象的信息。

2)Excel.Workbook workbook。Excel.Workbook类表示Excel应用程序中的单个工作簿。

3)Excel.Worksheet worksheet。Excel提供Sheets集合作为 Microsoft.Office.Interop.Excel.Workbook 对象的属性,但是Excel中没有Sheet类。相反,Sheets 集合的每个成员都是一个Microsoft.Office.Interop.Excel.Worksheet对象,或者是一个 Microsoft.Office.Interop.Excel.Chart对象。

4)Excel.Range workSheet_range。Excel.Range对象是Excel应用程序中最常用的对象。在能够处理Excel内的任何范围之前,必须将它表示为Range对象,并处理该对象的方法和属性。Range对象表示一个单元格、一行、一列、包含一个或多个单元格块(可以连续,也可以不连续)的单元格选定范围,甚至多个工作表中的一组单元格。

createExcel()方法用来创建Excel实例,也就是初始化声明的四个变量,实现代码如代码清单1-2所示。

代码清单1-2 初始化变量

public void createExcel()

{

app = new Excel.Application();

app.Visible = true;

workbook = app.Workbooks.Add(1);//创建workbook

worksheet = (Excel.Worksheet)workbook.Sheets[1];//创建worksheet

}

如代码清单1-2,Workbook对象由Application对象创建,Worksheet对象由Workbook对象创建。

addData()方法用来向表格中添加数据,四个参数分别为行、列、数据、数据格式,范围起始格、范围结束格。实现代码如代码清单1-3所示。

代码清单1-3 添加数据

worksheet.Cells[row, col] = data;

workSheet_range = worksheet.get_Range(cell1, cell2);

workSheet_range.Borders.Color = System.Drawing.Color.Black.ToArgb();

workSheet_range.NumberFormat = format;

Excel中的每一个格以行和列组成的坐标来唯一标识,这里行标识是数字,从1到n;列标识是字母,从A到Z,从AA到AZ……。

workSheet_range对象由worksheet.get_Range(cell1, cell2)方法来初始化,从cell1到cell2会被作为一个整体处理。workSheet_range.NumberFormat设置该区域内的字符格式化方式。

export()方法用来导出生成的Excel,实现如代码清单1-4所示。

代码清单1-4 导出Excel

public void export()

{

workbook.SaveCopyAs(@"D:/aa.xls");

app.Quit();

}

Workbook对象由三个方法用来保存Excel文件,分别为Save方法、SaveCopyAs方法和SaveAs方法,这里使用SaveCopyAs方法。保存之好调用Application对象的Quit()方法释放资源。

在本地测试一切正常,测试结果如图1-2所示。

1-2 测试结果

二.合并单元格与数字列标识转字母列标识

合并单元格的时候,必须要传递以字母表示的列标识给Excel.Range对象的.Mergeint)方法,但是我们取数据和填充数据使用的都是数字标识,这时候必须转成如图1-3的形式。

1-3 Excel的字母列标识

代码清单1-5提供的算法可解决这个问题。

代码清单1-5 数字列标识转字母列标识

public string ToName(int index)

{

if (index <= 0)

throw new Exception("invaild parameter");

index--;

List<string> chars = new List<string>();

do

{

if (chars.Count > 0)

index--;

chars.Insert(0, ((char)(index % 26 + (int)'A' )).ToString());

index = (int)((index - index % 26) / 26);

} while (index > 0);

 

return String.Join(string.Empty, chars.ToArray());

}

三. "异常来自 HRESULT:0x800A03EC "的原因

一不小心就会出"异常来自 HRESULT:0x800A03EC "的异常,原因很简单,Excel的行列都是从1开始的,如果我们习惯性的给worksheet.Cells[0, 0]或者worksheet.Cells[1, 0]或者worksheet.Cells[0, 1]赋值,就会引发该异常。

四. "未将对象引用设置到对象实例"和服务器端部署

客户端一切运行正常,接下来就是要把DLL部署到服务器上。可是服务器根本没用安装Office,在网站找了很久,也没找到此种方法的解决方案。无奈就安装了Office,本来以为万事大吉,但是每次都提示"未将对象引用设置到对象实例"。采用抛异常的方法才知道示例程序中的几个主要字段都为空,那就是本地的COM根本没调用成功。找到http://www.cnblogs.com/Mainz/archive/2009/11/11/microsoft_office_interop_excel.html文章,于是乎又进行了如下操作。

从服务器上把EXCEL.EXE拷到了本机上,然后从VS2010的命令行启动TlbImp,执行命令:TlbImp /out:Interop.Excel.dll Excel.exe。生成Interop.Excel.dll

在项目中去除了Microsoft.Office.Interop.Excel.dll的引用,添加Interop.Excel.dll,将顶部的using Excel=Microsoft.Office.Interop.Excel,该为using Excel= Interop.Excel,本地运行程序没有问题。再次更新服务器端程序,结果又出了新的异常:检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80080005

五. "80080005异常"与权限配置

"80080005异常"是应用程序对COM组件操作权限不足引起的。于是有了下面的操作:

1)控制面板->管理工具->组件服务->计算机->我的电脑->DCOM-> Microsoft Excel 应用程序

2)单击属性打开此应用程序的属性对话框。

3) 单击标识选项卡,然后选择交互式用户。

4) 单击默认安全性选项卡。设置当前服务器与ASP.NET相关的用户的访问权限。

5)单击启动权限的编辑默认值。设置ASP.NET相关的用户的访问权限。

至此,程序才运行成功,可谓一波三折。

六.关闭Excel进程

如果使用这种方式用户每导出一个Excel文件,服务器端就会启动一个Excel进程。这回引起两个问题,一是耗费服务器资源,二是当进程数达到上限时,会引发异常,调用COM失败。这个时候要想办法结束Excel进程。我采用了杀进程的方式,类似下面的做法:

private void DoExcel()
{
Microsoft.Office.Interop.Excel.Application application = new Microsoft.Office.Interop.Excel.Application();
//这里释放所有引用的资源
application.Quit();
KillExcel(application);
}

[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd,out int ID);
public static void KillExcel(Microsoft.Office.Interop.Excel.Application excel)
{
IntPtr t = new IntPtr(excel.Hwnd); //得到这个句柄,具体作用是得到这块内存入口

int k = 0;
GetWindowThreadProcessId(t, out k); //得到本进程唯一标志k
System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(k); //得到对进程k的引用
p.Kill(); //关闭进程k
}

 

 

 

posted @ 2010-11-24 16:49 陈典洪 阅读(129) 评论(0) 编辑

摘要: 转载自:飞鸟的博客 C# Excel操作类经常碰到需要操作Excel的情况,特别是涉及到DataTable和GridView之类东东的时候,导入导出Excel,并定制样式,调整字段等等的操作就成了家常便饭.[代码]阅读全文
posted @ 2010-11-24 16:46 陈典洪 阅读(206) 评论(0) 编辑

2010年8月1日 #

一、安装必备

启动SharePoint 2010安装程序,打开安装界面,点击“安装必备软件”,如下图所示,

进入系统所需软件检查,点击下一步,如下图所示:

 

接受许可协议,点击下一步,如下图所示:

进入必备安装界面,如下图:

 

系统必备安装完成,如下图:

 

二、SharePoint 2010安装

 

 

回到SharePoint 2010 安装界面,点击“安装 SharePoint Server”,如下图所示:

输入产品密钥,点击继续钮按,如下图所示:

接受协议条款,点击“继续”,如下图所示:

选择文件安装位置,点击“立即安装”按钮,如下图所示:

进入安装界面,等待系统安装,如下图:

点击“完成”按钮,打开SharePoint 产品配置向导,点击下一步,如下图所示:

确认继续配置向导,点击是按钮,如下图所示:

连接到服务器场,选择“创建新的服务器场”按钮,点击下一步,如下图所示:

进入配置数据库设置界面,填写数据库服务器名称,数据库访问帐号的用户名和密码,点击下一步,如下图所示:

填写服务器场安全密码,点击下一步,如下图所示:

进入配置管理中心web应用程序界面,指定端品号与选择此web应用程序的验证提供程序的类型,点击下一步,如下图所示:

进入确认配置信息界面,点击下一步,如下图所示:

进行SharePoint产品配置,如下图所示:

配置完成,点击“完成”按钮,如下图所示:

 

三、Web apps 2010 安装

启动web apps 2010安装程序,输入产品密钥,点击继续按钮,如下图所示:

勾选接受协议条款,点击继续按钮,如下图所示:

选择文件安装位置,点击立即安装按钮,如下图所示:

进入系统安装,耐心等待,如下图所示:

勾选“立即运行SharePoint 产品配置向导”复选框,点击关闭按钮。如下图所示:

打开SharePoint 产品配置向导界面,点击下一步,如下图所示:

确认继续配置向导,点击“是”按钮,如下图所示:

确认配置信息,点击下一步,如下图所示:

进行配置,请耐心等待,如下图所示:

完成配置,点击完成,如下图所示:

四、管理中心配置SharePoint

打开管理中心,配置SharePoint场页面,点击启动向导按钮,如下图所示:

进入服务向导界面,填写服务帐号,并勾选所要启动的服务,点击下一步,如下图所示:

启动服务过程,请等待,如下图所示:

五、创建站点

打开网站集创建界面,填写网站标题及选择当前网站集所使用的网站模板,点击确定按钮,如下图所示:

完成第一个网站集的创建,点击完成按钮,如下图所示:

打开IE,输入http://moss/查看创建的网站,如下图所示:

至此,sharepoint 2010安装布署完成。

posted @ 2010-08-01 00:52 陈典洪 阅读(353) 评论(0) 编辑

2010年7月27日 #

用infopath 引用外部数据源,进行数据操作,是一件非常方便的事情,比如连接SQL数据库,引用webServices、xml、sharepoint list等,但是我们发现了一个问题,infopath引用数据源时,会将数据缓存在客户端,当我们引用的数居源数据量大的时候,会产生用户操作缓慢的问题。这个时候我们希望下载下来数据能够,既小又准确。我们能够通过自定义数据源加参数的方法,实现动态的数据源查询。在VSTA中动态改变数据源查询参数与反回查询结果,可以参考如下代码:

 

代码
 public void CTRL1_14_Clicked(object sender, ClickedEventArgs e)
        {
            
// 在此处编写代码。
            System.Xml.XPath.XPathNavigator root;
            root 
= this.MainDataSource.CreateNavigator();
            DataConnection dc 
= ((DataConnection)DataSources["GetData"].QueryConnection);//获取数据源对象

            
if (dc is WebServiceConnection)
            {
                
string queryField = ""
                                     
+ "<tns:GetData xmlns:tns=\"http://tempuri.org/\"><tns:SecuCode>" + root.SelectSingleNode("//ns2:证券代码", this.NamespaceManager).Value + "</tns:SecuCode>"

                                   
+ "   <tns:TradingDay>" + root.SelectSingleNode("//ns2:查询日期"this.NamespaceManager).Value + "</tns:TradingDay>"
                                   
+ "   </tns:GetData>"
                                   
+ "";
                XmlDocument inputDocument
=new XmlDocument();
                inputDocument.LoadXml(queryField);
                XPathNavigator inputNav
= inputDocument.CreateNavigator();

                XmlDocument outputDocument 
= new XmlDocument();
               XPathNavigator outputNav 
= outputDocument.CreateNavigator();

                Microsoft.Office.InfoPath.WebServiceConnection fqc 
= (Microsoft.Office.InfoPath.WebServiceConnection)dc;

                fqc.Execute(inputNav, outputNav, 
null);//执行数据查询
                
//MessageBox.Show(outputNav.OuterXml);

                
string outXml = outputNav.OuterXml.Replace("xmlns=\"http://tempuri.org/\"", "");
                outputDocument.LoadXml(outXml);

                XmlElement nodeElement 
= (XmlElement)outputDocument.SelectSingleNode("GetDataResponse/GetDataResult/证券简称");
                XPathNavigator setNode 
= root.SelectSingleNode("//ns2:公司名称"this.NamespaceManager);
                DeleteNil(setNode);
                setNode.SetValue(nodeElement.InnerText);//对infopath域进行附值

                nodeElement 
= (XmlElement)outputDocument.SelectSingleNode("GetDataResponse/GetDataResult/交易日期");
                setNode 
= root.SelectSingleNode("//ns2:交易日期"this.NamespaceManager);
                DeleteNil(setNode);
                setNode.SetValue(nodeElement.InnerText);

            }
        }
        
public void DeleteNil(XPathNavigator node)
        {
            
if (node.MoveToAttribute(
               
"nil""http://www.w3.org/2001/XMLSchema-instance"))
                node.DeleteSelf();
        }

 

 

posted @ 2010-07-27 11:27 陈典洪 阅读(83) 评论(0) 编辑

在sharepoint 2010 中,excel2007或excel 2010文档格式,支持web app 应用,能够在浏览器在线打开,查看,但excel 2003格式的文档只能用office客户端打开,为了让上传的文档能够直接支持web app,只能将上传的excel 2003文档转换成excel 2007 文档再上传。文档转换的code如下:

 

代码
  //将excel2003转换成excel2007
                  MSExcel.Application excelApp = null;//提要   //word应用程序
                    MSExcel._Workbook excelDoc = null;    //word文档
                    Object nothing = Missing.Value;
                 excelApp 
= new MSExcel.ApplicationClass();

                 
string sourcePath = @"c:\excel2003.xls";      //原文件路径
                 excelDoc = excelApp.Workbooks.Open(sourcePath, nothing,
                         nothing, nothing, nothing, nothing,
                         nothing, nothing, nothing, nothing,
                         nothing, nothing, nothing, nothing,
                         nothing);
                   
                 
string targetPath =@"c:\excel2007.xlsx";//导出路径
                 object format = MSExcel.XlFileFormat.xlWorkbookDefault;//转换成新的格式

                    
//将新的exccel2007存到本地
                    excelApp.DisplayAlerts = false;//文档转换过程不要出现提示框
                    excelDoc.SaveAs(targetPath, format, nothing, nothing, nothing, nothing, MSExcel.XlSaveAsAccessMode.xlNoChange,
                               nothing, nothing, nothing, nothing, nothing);
                    excelDoc.Close(nothing, nothing, nothing);
                    excelApp.Quit();

 

 

posted @ 2010-07-27 10:48 陈典洪 阅读(698) 评论(0) 编辑

2010年7月26日 #

第一步:创建Feature

1、用VS2010 新建一个sharepoint 2010 的Empty Sharepoint Project 项目,名称为CustomRibbon。

2、在Features 目录上,添加一个Feature,名称为CustomRibbonButton。

3、定义Feature文件。打开CustomRibbonButton.template.xml文件,进行编辑并保存,代码如下:

 

 <?xml version="1.0" encoding="utf-8" ?>
 
<Feature Id="A8DA4BE9-8F82-4E94-9723-D51E8B5D683E"
  Title
="CustomRibbonButton"
  Description
="CustomRibbonButton"
  Version
="1.0.0.0"
  Scope
="Web"
  xmlns
="http://schemas.microsoft.com/sharepoint/">
  
<ElementManifests>
    
<ElementManifest Location="CustomRibbonElement\Elements.xml" />
  
</ElementManifests>
 
</Feature>

 

第二步:创建支持文件

1、在CustomRibbon项目上,添加新项,选择Empty Elements类项,名称为CustomRibbonElement。

2、定义支持文件。打开Elements.xml文件,进行编辑,代码如下:

代码
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
 
 
<CustomAction
   
    
Id="CustomRibbonButton"
    RegistrationId
="101"
    RegistrationType
="List"
    Location
="CommandUI.Ribbon"
    Sequence
="5"
    Title
="Move Documents">
    
<CommandUIExtension>
      
<CommandUIDefinitions>
        
<CommandUIDefinition Location="Ribbon.Documents.Manage.Controls._children">
          
<Button
              
Id="Ribbon.Documents.New.TestButton"
              Alt
="Move Documents"
              Sequence
="5"
              Command
="Test_Button"
              Image32by32
="/_layouts/images/CustomRibbon/network32.GIF"
              Image16by16
="/_layouts/images/CustomRibbon/network16.GIF"              
              LabelText
="Move Documents"
              TemplateAlias
="o1" />
        
</CommandUIDefinition>
      
</CommandUIDefinitions>
      
<CommandUIHandlers>
        
<CommandUIHandler
          
Command="Test_Button"
          CommandAction
="javascript:alert('Welcome To SharePoint 2010 !');" />
      
</CommandUIHandlers>
 
    
</CommandUIExtension>
  
</CustomAction>
 
</Elements>

 

备注说明:
  "CustomAction“部分:
  “Sequence” 属性,这个属性指定了我们要添加的按钮所在组中的位置。
   “Location” 属性,这里指定了这个按钮应该被添加到哪个Tab下的哪个组中,其格式为:Ribbon.[Tab].[Group].Controls._children


  "Command” 属性,这个属性将“CommandUIDefinition” 与“CommandUIHandler” 关联起来。
  “TemplateAlias” 属性,定义了这个按钮在页面中是32X32还是16X16,“o1”是32,“o2”是16。

  “CommandUIHandler” 部分:

  “Command” 属性与第19行的“Command” 相对应,以将Button与其操作关联起来。
  “CommandAction” 标记,在这个标记中我们将定义按钮被按下时将要执行的Javascript脚本。SharePoint 2010为我    们提供了丰富的Javascript API,通过这些API我们可以做更多的事情。

第三步:部署

1、选择CustomRibbon项目,查看属性,在SiteUrl属性上,填写部署的站点,如:http://moss

2、选择CustomRibbon项目,右键“部署”将进行自动部署

 

第四步:查看效果

1、打开一个文档库,选择一个条目,在文件这个标签上,就可以看到刚刚部署的这个ribbon 按钮了。

 

注:用VS2010进行sharepoint 2010的开发还是挺方便的,能够很好的跟sharepoint集成,方便开发,部署与调试。

 

 

 


posted @ 2010-07-26 13:25 陈典洪 阅读(377) 评论(0) 编辑

2009年12月19日 #

     最近在做数据库的时候,发现经常由于tempdb太大而造成的磁盘空间不足的问题,为了解决这个问题我们使用的一个解决办法是把tempdb移到一个新的位置.

下面是具体的操作步骤;
1、检查tempdb的逻辑名字和它的存在位置。可以使用下面语句:

SELECT name, physical_name
FROM sys.master_files
WHERE database_id = DB_ID('tempdb');

2、暂停数据库服务.
3、拷贝原来tempdb的文件到新的位置(原来文件位置可以通过上述查询得到)。
3、拷贝完毕后,启动数据库服务。
4、执行如下命令:
USE master;
GO
ALTER DATABASE tempdb 
MODIFY 
FILE (NAME = tempdev, FILENAME = 'E:\tempdb\tempdb.mdf');
GO
ALTER DATABASE  tempdb 
MODIFY 
FILE (NAME = templog, FILENAME = 'E:\tempdb\templog.ldf');
GO

在这里,name=tempdev 和templog是tempdb的逻辑名字,FileName='E:\temdb\tempdb.mdf'是tempdb的新位置.
5、最后检查tempdb移动是否成功。

SELECT name, physical_name
FROM sys.master_files
WHERE database_id = DB_ID('tempdb');
 
 原文地址 http://www.cnblogs.com/steven-zhou-2005/archive/2006/08/09/472042.html

 

posted @ 2009-12-19 14:52 陈典洪 阅读(194) 评论(0) 编辑

2009年12月9日 #

摘要: 转载自:禁用MOSS2007“我的网站”功能建立完Moss2007的SSP服务之后,默认会为所有验证用户打开“我的网站”的链接,如下图所示:并不是所有人都会需要这个功能的,我们可以通过一下的步骤禁用它:打开SSP管理界面,然后点击“个性化服务权限”默认设置如下:点开我们不想让其拥有个人网站的用户,然后把相应的权限去掉即可:再回...阅读全文
posted @ 2009-12-09 15:59 陈典洪 阅读(132) 评论(0) 编辑

2009年10月29日 #

摘要: 转载自:使用Exchange 2007搭建多域名邮件系统默认情况下Exchange Server 2007部署之后只管理一个域名下的邮件收发,这已经可以满足大部分企业的需求,但是满足不了一些大企业的需求,例如公司总部使用顶级邮件域名后缀,分公司使用二级邮件域名后缀,或者一些集团公司有好几个域名,每个子公司都使用不一样的域名,这个情况下,一个域名就满足不了企业业务的需求了. 因此我们有必要配置Exc...阅读全文
posted @ 2009-10-29 04:06 陈典洪 阅读(352) 评论(0) 编辑

2009年10月28日 #

摘要: 转载自: Exchange 2007 配置 一、Exchange 2007概述 Exchange 2007(也称为Exchange 12)邮件作为企业邮箱,为企业提供企业信息服务,可以利用Exchange 2007邮件系统和申请的符合企业个性化的外网域名来配置一个属于企业本身的邮件系统,也可以将这Exchange 2007邮件系统发布到外网上作为企业在互联网上与企业通信的一个通信平台。配置Exch...阅读全文
posted @ 2009-10-28 00:08 陈典洪 阅读(220) 评论(0) 编辑