解惑

解己之惑,解人之惑

分类:.net (第3页共4页)

讨厌的data execution prevention

这个是微软的一个安全补丁,但是搞得服务器非常的不稳定,经常会把Generic Host进程搞死,然后机器就不能联网访问了。
以前采取的是放任的方式处理的,把Computer Browser服务设置成死掉后自动重启能够一定程度上解决问题,但是有时候还是需要人工干预。
正规的做法是安装补丁KB958644,注意版本

MAPI32的Impersonate的问题

这个其实是 用代码创建MAPI的Profile的后续问题,因为我们把这个东西封装在Web Service里面供远程的其他程序调用,而这个Web Service的运行身份很重要,结合到底是谁?讲的,我们期望是可以通过Impersonate创建在我们指定的用户下面,但是MAPI32是根据当前的Process的用户身份,也就是Application pool的运行用户来读取注册表创建Profile的,所以Impersonate基本上没有用,有一些方法:http://blogs.msdn.com/stephen_griffin/archive/2005/04/13/407925.aspx ,但是基本上对我们不适用。

用代码创建MAPI的Profile

这个问题曾经折磨了我好几天,最终放弃了。
最后在其他同事的不懈努力下最终解决:

extern "C" __declspec(dllexport) bool CreateProfileWithIProfAdmin( LPTSTR szProfile,LPTSTR szMailbox,LPTSTR szServer)
{
    HRESULT         hr = S_OK;            // Result from MAPI calls.
    LPPROFADMIN     lpProfAdmin = NULL;     // Profile Admin object.
    LPSERVICEADMIN  lpSvcAdmin = NULL;      // Service Admin object.
    LPMAPITABLE     lpMsgSvcTable = NULL;   // Table to hold services.
    LPSRowSet       lpSvcRows = NULL;       // Rowset to hold results of table query.
    SPropValue      rgval[2];               // Property structure to hold values we want to set.
    SRestriction    sres;                   // Restriction structure.
    SPropValue      SvcProps;               // Property structure for restriction.

    // This indicates columns we want returned from HrQueryAllRows.
    enum {iSvcName, iSvcUID, cptaSvc};
    SizedSPropTagArray(cptaSvc,sptCols) = { cptaSvc, PR_SERVICE_NAME, PR_SERVICE_UID };

阅读全文

到底是谁?

Windows的IIS应用的身份真的是太复杂了一点。
首先是IIS的Service是有运行用户的
然后是应用使用的Application Pool也有运行用户
然后是应用也可以指定Impersonate的用户
而如果应用没有使用Windows的用户,那么还可能有另外一个用户。

以前没有搞过Windows的Web的开发,不太清楚这个里面的最佳实践。

目前的感觉是:
IIS的身份一般不去动,因为是大家共享的
如果需要比较强的用户身份,而且比较固定,建议修改Application Pool的运行身份,另外建议创建自己的Application Pool,如果应用只是简单的需要某种身份访问系统中的资源,例如读写文件、服务数据库,那么建议简单的修改web.config,使用Impersonate指定一个用户。

开始习惯MSDN格式的API文档了

最开始很不习惯MSDN格式的api文档,感觉很分散,原理性介绍、快速入门、API的说明以及常量定义都不知道怎么弄的。
经过对CDO的文档的摸索,发现这些东西都是存在的,只是和JAVA的那些习惯不一样,java的组件的文档一般比较全面,而且把这些东西组织得很好,开始就是quick start,然后是developement guide,最后就是API reference,链接也做得比较好。虽然MSDN的文档不缺少这些内容,在内容之间的引用做得似乎弱一些。

从CDO得到Mailbox的大小

前几天的方案都比较复杂一些,再来一个简单的:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MAPI;

namespace ConsoleApplication3
{
    class Program
    {
        [STAThread]
        static void Main()
        {
            Session session = new Session();
            session.Logon(null, null, false, true, 0, true, "exchange2007\nuser1");
            InfoStores infoStores = (InfoStores)session.InfoStores;
            for (int i = 0; i < (int)infoStores.Count; i++)
            {
                InfoStore infoStore = (InfoStore)infoStores.get_Item(i + 1);
                if (((string)infoStore.Name).IndexOf("Mailbox – ") >-1)
                {
                    Fields fields = (Fields)infoStore.Fields;
                    Field size = (Field)fields.get_Item(CdoPropTags.CdoPR_MESSAGE_SIZE, System.Reflection.Missing.Value);
                    Field count = (Field)fields.get_Item(CdoPropTags.CdoPR_CONTENT_COUNT, System.Reflection.Missing.Value);
                    Console.WriteLine(infoStore.Name + ": " + size.Value + "Bytes, messages:" + count.Value);
                }
            }
            session.Logoff();
            Console.ReadLine();
        }
    }
}

这个方案的问题是需要安装CDO,好在这个东东是微软的,而且很小,安装包才几百K,其实就是把MAPI的一些API包装成COM了,所以.net平台的那些语言都可以调。

历史遗留问题是微软的死穴

向后兼容性和历史上的诸多古老的解决方案对于微软阵营的开发者而言就是梦魇,它的多语言支持又是另外一个败笔。

我现在被迫从Java阵营临时到了微软阵营,但是遇到的问题多多。
现在有几个比较简单的任务:得到Exchange Server的邮件大小,Exchange本身没有API做这个事情,但是有一些其他的变通方式,例如得到所有的Mailbox然后统计每个Mailbox的大小,而Mailbox的大小也没有直接的API,需要统计所有的Folder的大小,虽然性能上不太好,但是总归是可以做到的。
目前发现的解决方案有这样几个:

  • 使用Exchange 2007的management shell带的Get-MailboxStatistics脚本,我们可以得到Exchange的某个Database的大小,但是缺点是需要在Exchange Server上运行,优点是可以很容易写出C#的代码。
  • 使用Exchange 2007的EWS,优点是可以写出C#代码,而且可以从其他机器运行,缺点是只支持2007版本
  • 使用MAPI32,问题是只能写c++代码,尝试使用DllImport直接使用MAPI32,但是到HrOpenExchangePrivateStore就出问题了,内存读写有问题,MAPIInitialize,MAPILogon,MAPILogoff等方法就没事。网上看到有人用c#封装了MAPI32,但是没有涉及到HrOpenExchangePrivateStore。

接下来只能尝试写COM组件把它包起来给c#用了。

从客户端得到Mailbox的Size

昨天已经搞定了从服务器端得到Mailbox的size,但是这样不是很方便,需要在Exchange服务器上发布代码,今天继续研究从客户端得到这个Size,历经磨难终于成功:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ConsoleApplication1.exchange2007;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace ConsoleApplication1
{
    class EWS
    {
        public static void Run()
        {
            ServicePointManager.ServerCertificateValidationCallback =
            delegate(Object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
            {
                return true;
            };
            ExchangeServiceBinding esb = new ExchangeServiceBinding();
            esb.RequestServerVersionValue = new RequestServerVersion();
            esb.RequestServerVersionValue.Version = ExchangeVersionType.Exchange2007;
            esb.Credentials = new NetworkCredential("Administrator", "password", "domain.com");
            esb.Url = "https://exchange2007/EWS/Exchange.asmx";

            Console.WriteLine("Administrator:" + GetMailboxSize(esb, "Administrator@domain.com"));
            Console.WriteLine("cherami:" + GetMailboxSize(esb, "cherami@domain.com"));
            Console.WriteLine("ES1Test1:" + GetMailboxSize(esb, "ES1Test1@domain.com"));

            Console.ReadLine();
        }

阅读全文

从Exchange2007得到Mailbox的大小

开始的时候觉得这个是一个很小的问题,肯定有API直接可以拿到的,不过看了一圈下来,给出的最多的建议是从MAPI得到Mailbox,然后遍历目录累加大小得到Mailbox的大小。可以参考微软的KB:
http://support.microsoft.com/kb/320071
http://support.microsoft.com/kb/200160/

不过感觉都很麻烦。Exchange 2007提供了Exchange Management Shell ,里面有个脚本命令Get-MailboxStatistics可以得到Mailbox的信息,其中就包括Mailbox的大小,然后可以用c#调用这个脚本:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
            PSSnapInException snapInException = null;
            PSSnapInInfo info = rsConfig.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out snapInException);
            Runspace myRunSpace = RunspaceFactory.CreateRunspace(rsConfig);
            myRunSpace.Open();
            Pipeline pipeLine = myRunSpace.CreatePipeline();
            Command myCommand = new Command("Get-MailboxStatistics");
            pipeLine.Commands.Add(myCommand);
            CommandParameter databaseParam = new CommandParameter("database", "Main Database");
            myCommand.Parameters.Add(databaseParam);
            Collection<PSObject> commandResults = pipeLine.Invoke();
            foreach (PSObject cmdlet in commandResults)
            {
                Console.WriteLine(cmdlet.Properties["DisplayName"].Value + "\t" + cmdlet.Properties["TotalItemSize"].Value);
            }
        }
    }
}

唯一的问题是这个需要在exchange server上执行,而且也不排除这个脚本也是通过遍历目录得到的大小(执行的速度似乎也不快)。

SandCastle使用入门

看了网上的SandCastle入门,但是我使用的时候还是遇到很多问题。
秉承我的一贯作风写个我的入门指南:

  • 下载SandCastle并安装
  • 设置系统环境变量DXROOT指向SandCastle安装的目录,默认是C:\Program Files\Sandcastle\
  • 把SandCastle的productiontools加到系统环境变量PATH里面%DXROOT%\productiontools;
  • 把SandCastle的example的bat文件拷贝出来备用:C:\Program Files\Sandcastle\Examples\sandcastle\build_Sandcastle.bat,建议把bat重命名为generate_chm.bat
  • 如果你使用Visual Studio,那么修改工程的属性,把Build的Output中的XML Documentation File勾中,如果没有使用Visual Studio,那么可以使用csc命令生成这个XML文件 csc /doc:Xxx.xml Xxx.cs,如果编译依赖其他的东西,也需要在命令行中提供。
  • Build工程,把Build生成的bin下的所有内容(debug或者release),注意是所有内容拷贝到其他的新建的目录下,然后把generate_chm.bat也拷贝过去,然后在DOS下进入那个目录: generate_chm vs2005 Xxx。不要直接在Visual Studio的工程下面运行,一个是生成很多中间的目录和文件,二是好像影响正常生成(我开始都是在Visual Studio下弄的,总是不成功)。
更早的文章 更新的文章

© 2024 解惑

本主题由Anders Noren提供向上 ↑