一切皆有可能

SLEEPY BUT POWERFUL (A.K.A 速马) Creative Commons License
随笔 - 43, 评论 - 483, 引用 - 14

导航

关于

我

联系方式 (夏桅 xia4 wei2)

译作

 

三章样章阅读
[CSDN读书频道提供]

 

想做点好事的来看看

一字不识的藏族同胞阿牛创办的完全免费学校

 

MVP Profile

Visual Developer - .NET/C#

Visitors

Locations of visitors to this page

标签

每月存档

最新留言

广告

【第1页/共4页,49条】
首页
前页
1
2007年05月08日

XBAP = XAML Browser Application

作为Windows Vista的重要feature,XAML在浏览器中的应用让我心动不已。不过这东西比HTML复杂,以前ASP.NET是浏览器端HTML/JavaScript+服务器端C#,HTML都是服务器端生成的;现在是浏览器端XAML/C#,服务器端可以没有,也可以是Web Service或者别的远程服务。JavaScript在浏览器里面能做的事情是很有限的,比如正常情况下不能访问文件系统;同样,运行在客户端的C#代码虽然能被自动加载,但也受安全沙箱模型限制。

假如你在运行在客户端的C#代码里面调用了个SqlCommand,那你的XBAP程序需要的安全级别就一下子变成了Full Trust。这会导致用户不能像访问普通网页一样访问你的XBAP程序,而需要通过MSI安装包安装,或者先下载个证书(就像下载ActiveX控件一样)。如果是一个普通的Internet应用,这显然不是理想的情况。

我想99%的Web应用都是需要访问数据库的。这样最佳设计应该是这样子:

XBAP (UI Layer) <-> Web Service (Business Layer) <-> Database

Business Layer里面可以根据需要分出数据层等等。

刚开始玩,写的这些东西可能不对,仅供参考。

参考:

http://scorbs.com/2007/01/10/xbap-trust-levels/http://scorbs.com/2006/11/09/wpf-internet-sandbox-feature-list-xbaps-loose-xaml/

posted on 2007-05-08 18:02:00 by sunmast  评论(12) 阅读(10100)

 
2007年04月17日

活动简介

2005年12月2日,随着微软正式在中国发布了 Visual Studio 2005 产品系列,越来越多的企业客户以及独立软件开发商开始使用 Visual Studio 2005 构建其企业应用程序。做为微软旗舰级平台工具,Visual Studio Team System 提供了对软件开发全生命周期的支持与管理,整合了微软三十多年的软件开发经验,让企业客户以及软件开发商可以站在巨人的肩膀上,打造成功软件。

为了帮助国内众多使用微软技术进行软件开发的企业和个人大幅提高软件开发的生产力,微软近期与各地微软.NET俱乐部一起合作,推出 Visual Studio 2005 Team System 专场巡展活动,展示 VSTS 是怎么进一步为开发人员提高开发生产力以及它又怎么帮助软件团队构建强壮和可靠软件的。希望俱乐部的会员和非会员都能通过本次活动对 VSTS 有进一步的认识。

活动的内容将基本涵括

  • 基于Visual Studio Team System的解决方案概述
  • 基于MSF4.0的方法论及VSTS支撑环境 软件生命周期简介
  • 如何组建软件团队及在TFS上定义团队的角色和责任
  • 企业级源代码管理和BUG管理
  • 介绍Team Architect设计理念、Team Architect设计方案
  • 测试相关内容
  • VSTS DEMO

活动时间:4月21日(本周六)  14:00-17:30
活动地点:上海市淮海中路1555号 上海图书馆
坐车路线:26、911、926、945、920、830、96、93、15、548等高安路或上海图书馆站;地铁一号线衡山路站


主页:http://www.techjie.com/

注册:http://www.techjie.com/usermodules/register.aspx

posted on 2007-04-17 17:44:00 by sunmast  评论(2) 阅读(8017)

 
2007年02月14日

http://www.youtube.com/watch?v=KyLqUf4cdwc

Really funny

posted on 2007-02-14 13:55:00 by sunmast  评论(8) 阅读(9385)

 
2006年12月31日

这个post主要用来share我的IdentityScope类

在Windows Vista运行Visual Studio 2005(without SP1)时,最好使用Vista的Run as administrator的功能,否则有些功能就不能正常工作。而在我们开发的.NET程序内部,有时也会碰到需要临时提高权限的情形。ASP.NET程序员经常问的一个问题是,我的代码为什么没有权限创建一个文件?基本的解决方案有三个:

  • 提升ASPNET帐户(在Windows 2003则是Network Service)的权限(不推荐)
  • 为目标文件或文件夹设置ASPNET帐户的读写权限(如果需要访问的文件路径是固定的)
  • 在web.config设置impersonate,以另一个帐户的身份运行程序,比如Administrator...

论坛和新闻组里面常出现的另一个问题是,如何访问网上邻居或者映射的网络驱动器?常见的答案是使用Process.Start方法调用cmd.exe执行一个net use命令,这个方案是可行的但是显然不科学... 这里同样是权限问题。

.NET类库自带了个WindowsImpersonationContext类,可以用来进行用户身份模拟。不过创建这个对象的唯一办法调用WindowsIdentity.Impersonate(IntPtr userToken)方法,而userToken却只有通过Windows API调用而来(根本就是没打算让人用的)... MSDN上语焉不详,而实际上Windows SDK解释的更清楚,在LogonUser页有完整的说明和示例。于是使用P/Invoke封装了LogonUser、ImpersonateLoggedOnUser、RevertToSelf这几个API以及相关的一些枚举类,实现了一个IdentityScope类。演示代码:
Console.WriteLine(WindowsIdentity.GetCurrent().Name);
using (new IdentityScope("SUMA-LP", "Administrator", "********"))
{
    Console.WriteLine(WindowsIdentity.GetCurrent().Name);
}
Console.WriteLine(WindowsIdentity.GetCurrent().Name);

Console将输出:
Redmond\V-Wexia
SUMA-LP\Administrator
Redmond\V-Wexia

你可以看到在这个using代码块里面执行者身份成功的扮演了本机的Administrator。在访问网上共享资源的时候这个类同样有效,比如:
using (new IdentityScope("Domain", "User", "Password", LogonType.NewCredentials, LogonProvider.WinNT50))
{
    File.Copy("file.ext", "\\shared\folder\file.ext");
}

这里使用LogonType.NewCredentials登陆类型意味着本地身份不变,访问网络资源时使用扮演的身份。

IdentityScope类的源代码见:http://blog.joycode.com/sunmast/articles/identityscope_class.aspx

posted on 2006-12-31 04:31:00 by sunmast  评论(5) 阅读(12246)

 

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace Sunmast.SharedCode
{
    /// <summary>
    /// The type of logon operation to perform.
    /// </summary>
    enum LogonType : uint
    {
        /// <summary>
        /// This logon type is intended for users who will be interactively using the computer, such as a user being logged on by a terminal server, remote shell, or similar process. This logon type has the additional expense of caching logon information for disconnected operations; therefore, it is inappropriate for some client/server applications, such as a mail server.
        /// </summary>
        Interactive = 2,
        /// <summary>
        /// This logon type is intended for high performance servers to authenticate plaintext passwords. The LogonUser function does not cache credentials for this logon type.
        /// </summary>
        Network = 3,
        /// <summary>
        /// This logon type is intended for batch servers, where processes may be executing on behalf of a user without their direct intervention. This type is also for higher performance servers that process many plaintext authentication attempts at a time, such as mail or Web servers. The LogonUser function does not cache credentials for this logon type.
        /// </summary>
        Batch = 4,
        /// <summary>
        /// Indicates a service-type logon. The account provided must have the service privilege enabled.
        /// </summary>
        Service = 5,
        /// <summary>
        /// This logon type is for GINA DLLs that log on users who will be interactively using the computer. This logon type can generate a unique audit record that shows when the workstation was unlocked.
        /// </summary>
        Unlock = 7,
        /// <summary>
        /// This logon type preserves the name and password in the authentication package, which allows the server to make connections to other network servers while impersonating the client. A server can accept plaintext credentials from a client, call LogonUser, verify that the user can access the system across the network, and still communicate with other servers.
        /// </summary>
        NetworkClearText = 8,
        /// <summary>
        /// This logon type allows the caller to clone its current token and specify new credentials for outbound connections. The new logon session has the same local identifier but uses different credentials for other network connections.<br/>
        /// This logon type is supported only by the LOGON32_PROVIDER_WINNT50 logon provider.
        /// </summary>
        NewCredentials = 9
    }

    /// <summary>
    /// Specifies the logon provider.
    /// </summary>
    enum LogonProvider : uint
    {
        /// <summary>
        /// Use the standard logon provider for the system.<br/>
        /// The default security provider is negotiate, unless you pass NULL for the domain name and the user name is not in UPN format. In this case, the default provider is NTLM.
        /// </summary>
        Default = 0,
        /// <summary>
        /// Use the Windows NT 3.5 logon provider.
        /// </summary>
        WinNT35 = 1,
        /// <summary>
        /// Use the NTLM logon provider.
        /// </summary>
        WinNT40 = 2,
        /// <summary>
        /// Use the negotiate logon provider.
        /// </summary>
        WinNT50 = 3,
    }

    /// <summary>
    /// Use identity scope to impersonate a different user
    /// </summary>
    class IdentityScope : IDisposable
    {
        [DllImport("Advapi32.dll")]
        static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword,
            LogonType dwLogonType, LogonProvider dwLogonProvider, out IntPtr phToken);
        [DllImport("Advapi32.DLL")]
        static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
        [DllImport("Advapi32.DLL")]
        static extern bool RevertToSelf();
        [DllImport("Kernel32.dll")]
        static extern int GetLastError();

        bool disposed;

        public IdentityScope(string domain, string userName, string password)
            : this(domain, userName, password, LogonType.Interactive, LogonProvider.Default)
        {
        }

        public IdentityScope(string domain, string userName, string password, LogonType logonType, LogonProvider logonProvider)
        {
            if (string.IsNullOrEmpty(userName))
            {
                throw new ArgumentNullException("userName");
            }
            if (string.IsNullOrEmpty(domain))
            {
                domain = ".";
            }

            IntPtr token;
            int errorCode = 0;
            if (LogonUser(userName, domain, password, logonType, logonProvider, out token))
            {
                if (!ImpersonateLoggedOnUser(token))
                {
                    errorCode = GetLastError();
                }
            }
            else
            {
                errorCode = GetLastError();
            }
            if (errorCode != 0)
            {
                throw new Win32Exception(errorCode);
            }
        }

        ~IdentityScope()
        {
            Dispose(false);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    // Nothing to do.
                }
                RevertToSelf();
                disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}

posted on 2006-12-31 04:29:00 by sunmast  评论(1) 阅读(2612)

 
2006年12月28日

原来只是打算实现一个进程互斥的功能,而.NET似乎没有内置,所以决定调Windows API自己写。原来简单的几句代码,加上了Exception Handling和Dispose Pattern后,居然搞出了近一百行代码,还没怎么写注释。

/// <summary>
/// Process level simple mutex class. By Sunmast.
/// </summary>
/// <remarks>
/// Always avoid duplicate mutex names.
/// </remarks>
class ProcessMutex : IDisposable
{
    [DllImport("Kernel32.dll")]
    static extern IntPtr CreateMutex(IntPtr lpMutexAttributes, bool bInitialOwner, string lpName);
    [DllImport("Kernel32.dll")]
    static extern bool ReleaseMutex(IntPtr hMutex);
    [DllImport("Kernel32.dll")]
    static extern uint WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);

    const uint WAIT_ABANDONED = 0x00000080;
    const uint WAIT_OBJECT_0 = 0x00000000;
    const uint WAIT_TIMEOUT = 0x00000102;
    const uint WAIT_FAILED = 0xFFFFFFFF;
    const int MAX_PATH = 260;

    IntPtr hMutex;
    bool disposed;

    public ProcessMutex(string mutexName)
        : this(mutexName, int.MaxValue)
    {
    }

    public ProcessMutex(string mutexName, int timeout)
    {
        if (mutexName == null)
        {
            throw new ArgumentNullException("mutexName");
        }
        if (mutexName.Length > MAX_PATH)
        {
            throw new PathTooLongException("The name is limited to MAX_PATH characters.");
        }
        hMutex = CreateMutex(IntPtr.Zero, false, mutexName);
        if (hMutex == IntPtr.Zero)
        {
            throw new InvalidOperationException("Mutex creation failed.");
        }
        uint waitResult = WaitForSingleObject(hMutex, timeout);
        switch (waitResult)
        {
            case WAIT_TIMEOUT:
                throw new TimeoutException("Cannot get mutex ownership due to time-out.");
            case WAIT_OBJECT_0:
                break;
            case WAIT_ABANDONED:
                throw new InvalidOperationException(
                    "The specified object is a mutex object that was not released by the " +
                    "thread that owned the mutex object before the owning thread terminated.");
            case WAIT_FAILED:
                throw new InvalidOperationException("Function failue.");
            default:
                break;
        }
    }

    ~ProcessMutex()
    {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Nothing to do.
            }
            ReleaseMutex(hMutex);
            disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

其用法有点类似C#的lock关键字,可以定义一个scope,例:

using (new ProcessMutex("MUTEX_TEST"))
{
    Console.WriteLine("Wait for ENTER key pressed.");
    Console.ReadLine();
}

看来白忙了,.NET已经内置了这个功能了。原来一直以为所有的WaitHandle都是线程级别的...

posted on 2006-12-28 15:42:00 by sunmast  评论(9) 阅读(9333)

 
2006年12月11日

Windows Vista系统内置了CD/DVD光盘刻录功能,当然,这个功能在Windows Media Player里面早已提供,但它现在和文件系统已经集成,功能上算不上强大,但使用上很傻瓜。对于普通用户的简单刻录需求,可以说简单够用。

有两个途径,一是右键点击要刻录的文件或者文件夹,选择Send To,再选择DVD RW Drive (E:),就可以了(机器不同则菜单上有细微差别,我的是DELL 640m)

或者在资源管理器里面直接打开DVD RW Drive,此时在工具栏上会出现一些按钮,比如Burn to disc和Erase this disc。这时候可以直接CTRL+A选中所有文件并删除(如果你不想续刻),把要刻录的文件或文件夹直接拖进去... 就像操作一个Flash Drive一样(有了这个功能还买什么DVD-RAM刻录机?)

实在是太简单了,不想详细描述。但下面的问题是光盘镜像文件怎么刻录?我没找到(谁找到了请在下面留言)。问题不大,以前记得Windows Server 2003的一个Resource Kit里面有这个功能,下载地址请点这里。这是个12MB的一个自解压包,不过如果你只关心刻录工具,那大部分都是没用的... 下载之后用7-Zip(或者WinZIP、WinRAR等)打开,在rktools.msi里面看到cdburn.exe和dvdburn.exe这两个文件。把它们解压缩到C:\DVRW(或者其它路径)

然后就可以刻录镜像文件了,比如我打算把刚下载的en_office_business_contact_manager_2007_X13-05848.iso刻录到我的一张DVDRW光盘里面,那么打开命令行界面输入:

C:\DVRW>dvdburn E: D:\Software\en_office_business_contact_manager_2007_X13-05848.iso

如果光盘里已经有东西则自动帮你擦除光盘(假如是RW)

这两个工具的用法如下:

C:\DVRW>cdburn -help
Usage:
        cdburn <drive> -erase [image [options]]
        cdburn <drive> image [options]
Options:
        -erase            Erases the disk before burning (valid for R/W only)
        -sao              Writes the image out in "session at once", or cue sheet, mode (default is "track at once")
        -speed            Speed of burn, or 'max' for maximum speed
        -imagehaspostgap  Use if your image already contains a 150 sector postgap
        The [image] must be provided unless the -erase flag is set.
        If both an image and -erase are provided, the media will be erased prior to burning the image to the disc.
  
C:\DVRW>dvdburn -help
Usage: dvdburn <drive> <image> [/Erase]

最后,除了给普通用户提供的刻录功能,系统还公开了刻录API — 微软一贯风格。这个不是Windows Vista的新功能了,事实上它是Windows Media Player API的一部分。参考:Windows Media Player 11 SDK IWMPCdromBurn Interface。如果没有记错的话,WMP 9就已经有这个接口了。

----- Update on 7/30/2007

今天翻UDF文件格式的资料的时候才发现IMAPI才是用来管光盘刻录的,WMP的那个只是专门用来把mp3刻成CD。

看这个:http://msdn2.microsoft.com/en-us/library/aa364817.aspx

里头有个例子:

' This script burns data files to disc in a single session 
' using files from a single directory tree.
 
' Copyright (C) Microsoft Corp. 2006

Option Explicit

' *** CD/DVD disc file system types
Const FsiFileSystemISO9660 = 1
Const FsiFileSystemJoliet  = 2
Const FsiFileSystemUDF102  = 4

WScript.Quit(Main)

Function Main
    Dim Index                ' Index to recording drive.
    Dim Recorder             ' Recorder object
    Dim Path                 ' Directory of files to burn
    Dim Stream               ' Data stream for burning device
    
    Index = 1                ' Second drive on the system
    Path = "g:\BurnDir"      ' Files to transfer to disc

    ' Create a DiscMaster2 object to connect to optical drives.
    Dim g_DiscMaster
    Set g_DiscMaster = WScript.CreateObject("IMAPI2.MsftDiscMaster2")

    ' Create a DiscRecorder object for the specified burning device.
    Dim uniqueId
    set recorder = WScript.CreateObject("IMAPI2.MsftDiscRecorder2")
    uniqueId = g_DiscMaster.Item(index)
    recorder.InitializeDiscRecorder( uniqueId )

    ' Create an image stream for a specified directory.
    Dim FSI                  ' Disc file system
    Dim Dir                  ' Root directory of the disc file system
    Dim dataWriter    
        
    ' Create a new file system image and retrieve root directory
    Set FSI = CreateObject("IMAPI2FS.CFileSystemImage")
    Set Dir = FSI.Root

    'Create the new disc format and set the recorder
    Set dataWriter = CreateObject ("IMAPI2.MsftDiscFormat2Data")
    dataWriter.recorder = Recorder

    FSI.FreeMediaBlocks = datawriter.FreeSectorsOnMedia
    FSI.FileSystemsToCreate = FsiFileSystemISO9660
        
    ' Add the directory and its contents to the file system 
    Dir.AddTree Path, false
        
    ' Create an image from the file system
    Dim result
    Set result = FSI.CreateResultImage()
    Stream = result.ImageStream
    
    ' Write stream to disc using the specified recorder.
    WScript.Echo "Writing content to disc..."
    dataWriter.write(Stream)

    WScript.Echo "----- Finished writing content -----"
    Main = 0
End Function
你甚至可以用这套API制作ISO镜像文件。同时支持ISO9660、Joliet和UDF。

posted on 2006-12-11 03:05:00 by sunmast  评论(2) 阅读(14767)

 
2006年12月02日

独自来Redmond, WA已经快一周了,这是我第一次到美国,举目无亲,公司的联系人也不管不问。幸运的是,期间展波同学(or大哥,maybe大叔)给予了我无数帮助(包括:带我去吃各国美味、订电话卡、买鸡翅、改进女友关系等无数事务)

感谢展波!

posted on 2006-12-02 01:40:00 by sunmast  评论(17) 阅读(11035)

 
2006年11月23日

这个post要表达的东西是非常基本而且简单的,但我已经反复考虑了数月之久。这里的程序指的是个人/家用桌面程序,非所谓的“企业级应用”。

几周前我在整理我家里电脑的相册时,PC和Laptop之间的相册不同步,COPY来COPY去实在是太繁琐了。而我在公司的另一台Laptop也带回家后,这变成了一个更麻烦的问题。解决这个问题的办法是找个文件夹同步软件。

在另外一个方面,假如我在父母住处也想看看我的相册怎么办呢?答案是我最好创建一个网上相册,比如Windows Live的Gallery服务,Google的Picasa相册,或者是其他网上大量的网络相册服务。而这里的问题是,网络太慢了,桌面程序点一下Page Dn就能翻一个相片,网上有时候要一分钟。

我的电子邮件也有着类似的问题。如果使用Outlook收邮件的话,收下来后服务器上就没了,这意味着我不能在另外一台电脑上再去查看这个邮件。对于工作邮件这可能不是个问题,但个人邮箱却没有办法。于是很多人选择了全部基于Web界面处理个人邮件,比如Gmail和Live Mail。

但更为理想的状况是,我可以用Outlook收发邮件,用Word编辑邮件,同时邮件在服务器上总是保存着副本(这可以设置Outlook下载邮件后不删除服务端邮件,但邮箱容量往往都很小,不能长期这么做,现有邮件系统也不把这种需求当作典型应用)。邮件服务器上不但保存一个一个邮件,还有我设置的邮件分类,还有已读/未读状态值,甚至Outlook的Flag和Task等。这样无论我在哪里打开Outlook,都是一样的体验。

我现在使用Google的Picasa相册已经有了部分的这种能力,它同时有桌面和Web版本,我曾对它寄予完全的希望,用来管理我所有的相片。但如果不是我孤陋寡闻,显然Google并没有考虑到这个方面,因为Picasa桌面端只能向Web端上传图片却不能下载。。。而更进一步的设计则应该是具有本地文件和Web数据库同步的功能。

Windows Live的Favorites似乎有着一模一样的问题,它允许你从IE的Favorites导入到Web端,但却没有反向同步的能力。。。但它相比Picasa的优点是,客观上它是支持导出的,但是只是导出到一个HTM文件让你下载而已。。。而不是自动“装”到IE收藏夹所在的文件夹内。

微软的Share Point Service加上Office则是个更接近理想的组合:

  • 数据保存在服务端的数据库里,你在任意网络可连通的地方都可打开
  • Office一系列桌面软件安装于客户端,可以用这些软件来打开修改文档

这个组合在我看来已经接近完美了,但唯一的问题是在离线状态文档就不可访问了。我们需要文件在硬盘上的Cache。当然,SPS/WSS主要还是针对企业应用的,这个问题不大,网络速度一般也不会成为问题,数M的Word文件在数秒内就能传输完成。但如果Office System在客户端再加个“Share Point Client”维护硬盘Cache的话,那就更棒了。

这里的Model是相当简单的:

数据(Online,公共服务器维护,受安全措施保护)
↑↓
缓存(Offline,程序自动维护)
↑↓
程序(Offline,自维护或者IT管理员维护)

作为可选项,公共服务器上可以支持Web版的数据查看和一些简单操作 — 如果有必要的话。

至于Google的在线版本的Word和Excel,则根本是误入歧途(我不是作为一个MS MVP下这个结论的)。Google的选择是把程序和数据统统放在服务端,这大概是大部分对Google这些服务心存怀疑态度的人的最根本出发点。Web程序最终是不可打败桌面程序的,就算有下一代的DHTML可以做到和现有桌面程序一样的用户体验(比如Word般丰富的文本编辑器),他仍然需要硬盘的Cache。且不说这是个相当大的假设,更不用说微软的WPF加Expression套件在Rich Client方面已经再次走在了前面。也许五年后网络速度和连通性又有了非常大(速度*=100,连通性100%,网络延迟100ms内)的提高,硬盘Cache无足轻重,那基于浏览器的应用还面临着最后一个问题,那就是它们必定受限于浏览器安全沙箱模型,可触及的数据和可做的动作都是受限的。

Google的Picasa软件离这个目标则只有一步之遥。但令人匪夷所思的是,他们为什么不在Gmail这样的产品上也应用类似的策略呢?Gmail Notifier都做出来了,再进一步吧。Gmail的Web界面编辑器确实“还算不错”,但也只是相对于其它Web编辑器而言而已,距离Outlook等桌面软件差太远了。

除了这些用户关注的数据,其它程序本身使用的数据也可放在网上。比如说配置文件。极端一点,想象一下把整个Windows注册表都同步到网上的情形(当然硬件相关的配置信息就不用了),至少你能节约大量重装系统的时间(装系统很快,但装软件配置软件很慢)。Q3ACN(一个游戏网站)曾提供过保存Quake3游戏CFG文件的服务,大受欢迎,因为这样我们Quaker随便去哪个网吧都能以自己的CFG文件配置游戏系统,提高作战水平。要是id Soft直接把这个功能植入游戏,再在公司的Server上提供数据库接口,那就更完美了。(这是个坏例子,不打Quake游戏的朋友可能很难理解这一点。。。)

最后,关于SaaS(Software as a Service),这也是一个很好的切入点,虽然这个和SaaS只有一丁点关系。。。程序除了使用更好的加密算法防止盗版(比如微软的SPP),还可结合Internet。让程序的一部分功能依赖于Internet上的Server,可以非常轻松的获得非常好的保护。破解的Xbox360能玩单机游戏,却不能玩联网游戏,这就是个良证。把程序所需的配置数据放在互联网上,也是实现这个目的的途径之一。是不是合适,这是另外一个问题,这里的假设是你希望保护好你的软件并为你带来利润,而不是一个FOSS偏执狂。

刚才Kaneboy提示,Office 2007的Groove已经具备了我所需要的"Share Point Client"的功能,当然它的feature还不止这些,呵呵。

updating

posted on 2006-11-23 23:34:00 by sunmast  评论(10) 阅读(10571)

 
2006年11月21日
.NET企业服务框架

思归和我翻译的《.NET企业服务框架》一书终于面世了,在这里可以看到相关的介绍和购买信息(第二书店上也有)。

目录 | 译者序 | 前言 | 作者序

这是一本介绍.NET Enterprise Service的书,做企业开发的开发者,一定能在这本书里找到你想要的东西这里有3个章节的在线版本

我还新建了一个Google Group,有任何关于这本书的问题都欢迎来这里讨论:

Google Groups .NET企业服务框架
Browse Archives at groups.google.com

最后,这本书本来预期是今年上半年上市的(我春节就交稿了),但由于各种各样的原因居然拖到了现在。对一直关注这本书的朋友们说一声SORRY!

posted on 2006-11-21 18:19:00 by sunmast  评论(8) 阅读(9188)

 
2006年11月09日

--- 写在Vista RTM之日的流水帐

今年7月我转到了新公司,新部门,从头开始建设新的开发团队。作为一个理想主义者,原来打算直接上TFS(Team Foundation Server)的。。。不过对于这么小的Team,TFS太贵了点,有浪费之嫌。而现有的正版资源是,Windows 2003 STD,Office 2003 PRO,和Visual Studio 2005 STD。于是乎,我打算用WSS(Windows Sharepoint Service,Windows 2003的一个免费组件)做项目门户、共享文档、文档(with版本)管理等,用VSS 8.0做配置管理(有了VS或者Office的License后VSS就是免费的),再开一个File Server来放工具、软件等等。

但Bug管理的问题却一直没想好怎么办。原来在Infosys用的是Excel + RADAR,显然不能用;再之前是Clear Quest,还是太贵。Test Director和Silk Test之类的我也不想买。。。于是乎,在网上看各种免费Bug管理工具的评价和测试报告,最终圈定在了这三个(分先后):BugFree、Mantis,和BugZilla。BugFree是一个微软员工写的,据说贯彻了微软Bug管理的核心思想。。。不过我觉得它的数据统计和报表的功能不尽如人意。而Mantis和BugZilla都是老牌的开源Bug管理工具了,但对我来说他们的安装和配置实在是太恼人了,在我还没有开始尝试使用他们之前,就放弃了(准确的说是,我只能用用online的demo)。而BugFree的代码更不能让人放心,似乎有绝对路径/相对路径的错误,安装过程还得自己去改它代码,搞死人啊。此外,它们似乎也都是使用内建的帐户管理系统,而我希望它能和AD集成。

在以前的公司里,我们常常用Bug管理工具管Task,而其实反过来也问题不大。想想我们究竟关注Bug管理工具的什么功能?除了基本的纪录每个Bug的各种属性信息以外,还需要支持方便的查询,邮件通知,还有统计报表,等等。对于开发/测试者来说,要能方便的纪录Bug信息,管理Bug生命周期;而对管理者来说,需要准确的统计数据以支持决策。Bug管理和Task管理在某种程度上是相当类似的,WSS的Task List的自定义能力又正好非常的强(没装过WSS的赶快装一个看看吧,WSS 3.0都快出来了),那么为什么一定要找一个专门为Bug管理定制的软件呢?我打算开始在项目里面尝试使用Task List管理Bug。就算还没能100%满足要求,但自定义的Task List可以作为一个起点,要知道WSS是支持二次开发的。如果你愿意,基于WSS搞一个集成了需求管理、缺陷管理等等的Product Studio出来也不是不可能。。。

-----

看到Alex的回复,重新考虑了下,可能Discussion List确实比Task List更适于做Bug Tracker。。。

posted on 2006-11-09 16:31:00 by sunmast  评论(17) 阅读(10142)

 
2006年10月31日

BTW,刚才上MSDN订阅主页看到,Windows Vista和Office 2007将在七天内RTM,可以在MSDN订阅下载。WOW,终于一起来了。

BTW2,祝万圣节快乐!

posted on 2006-10-31 14:45:00 by sunmast  评论(10) 阅读(9167)

 
2006年10月18日

演讲主题(一):基于 WinFX 技术构建的下一代企业应用
主讲:钟卫

演讲主题(二):Windows Vista内核演进
主讲:张银奎

活动时间
2006年10月22日(周日) 14:00-17:00

活动地点
上海华东师范大学中山北路校区中山北路3663号,活动中心报告厅(到华东师范大学正门,直走至丽娃河,在河北岸左转,直走即到)

目标成员
IT开发人员、软件开发经理、软件架构师、IT知识工作者、系统管理人员、信息主管等。

报名注册
用户在 www.TechJie.Com 官方网站报名注册后,我们将对用户进行核准筛选,并在活动前通过电子邮件发出活动邀请函。活动完全免费,并有精美奖品附送。

报名链接:http://www.techjie.com/usermodules/register.aspx

详情请见:http://www.techjie.com/

posted on 2006-10-18 13:07:00 by sunmast  评论(4) 阅读(8885)

 
2006年10月10日

温昱(0,1,2,3,4,5)的《软件架构设计》共 26 章,分为 3 篇:

  • 软件架构概念与思想篇
  • 软件架构设计方法与过程篇
  • 程序员成长篇

详细目录现在还不能公布(尚未得到出版社许可)。

下面是作者的一些文章和演讲稿,供朋友们管窥本书:

所有对国产书籍嗤之以鼻的人,不妨读一读这本,它也许能改变你的看法。

posted on 2006-10-10 10:10:00 by sunmast  评论(14) 阅读(11495)

 
2006年09月29日

Anonymous Method - Lambda Expression

Lambda表达式是C# 3.0的新特性之一,最简单的Lambda表达式,像这样的:

Func<int,int> f = x => x + 1;

会被编译为一个方法:

int f(int x)
{
return x + 1;
}

所以它和匿名方法的实现很类似,可以说是匿名方法的带类型推导精简版本。和匿名方法一样,这是一种编译器行为;但是除了更“甜”的语法之外,C# 3.0进一步表现出了不少Functional Programming的特性,虽然还不是很“纯”(大概是受到强类型语言总思路的制约吧)。

和Lambda Expression相关的,C# 3.0还有个叫作Expression Tree的概念。这是它和Anonymous Method所不同的地方,Expression Tree不会被直接编译成一个实际的方法,而是编译成一个类似CodeDOM的语法树。比如:

Expression<Func<int, bool>> exprLambda = x => (x & 1) == 0;
// 请对比:Func<int, bool> nonExprLambda = x => (x & 1) == 0;

会被编译为:

ParameterExpression xParam = Expression.Parameter(typeof(int), "x");
Expression<Func<int, bool>> exprLambda = Expression.Lambda<Func<int, bool>>(
    Expression.EQ(
        Expression.BitAnd(xParam, Expression.Constant(1)),
        Expression.Constant(0)),
    xParam);

这个变量exprLambda是一个真正的方法,而不是一个方法指针(delegate/代理)。C# 3.0 Specification:“Following these assignments, the delegate f references a method that returns x + 1, and the expression tree e references a data structure that describes the expression x + 1.”它是方法体本身的描述,就像CodeDOM那样,通过代码描述代码,并且可以被编译、执行(不过这些动作都是透明的)。显然,和CodeDOM一样,你也可以遍历这个树,修改树结点,或者做一些别的特别的事情。这将使C#变得更加动态化(当然cost就是性能低一点点)。

*LINQ

LINQ/DLINQ/XLINQ(以及YLINQ、ZLINQ等等什么LINQ)是基于Lambda语法的。不过这里也存在着大量的语法糖(OK,只要没有带来负面作用那这个词也不是贬义词),比如这句:

from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total }

等价形式为:

customers.Join(orders, c => c.CustomerID, o => o.CustomerID,
 (c, o) => new { c.Name, o.OrderDate, o.Total })

所以*LINQ也是个编译器特性(与CLR无关)


一切改变都很酷,也确实能提高开发效率,不过我唯一觉得不喜欢的是,C# 3.0一下子引入了这么多的新语法,它已经从一个短小精悍的语言变得越来越复杂了。。

Reference

C# 3.0 Language Specification
http://download.microsoft.com/download/5/8/6/5868081c-68aa-40de-9a45-a3803d8134b8/csharp_3.0_specification.doc

C# 3.0 and LINQ - Expression Trees
http://www.interact-sw.co.uk/iangblog/2005/09/30/expressiontrees

posted on 2006-09-29 15:57:00 by sunmast  评论(13) 阅读(9887)

 
【第1页/共4页,49条】
首页
前页
1

Powered by: Joycode.MVC引擎 0.5.2.0