[转载]泛型 List 和 Dictionary 类的互相转换

mikel阅读(1352)

[转载]泛型 List 和 Dictionary 类的互相转换 – snapping – 博客园.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace testcs
{
    class Program
    {
        static void Main(string[] args)
        {
            ListAndDictionary();

        }

        /// <summary>
        /// 泛型 List 和 Dictionary 类的互相转换
        /// </summary>
        private static void ListAndDictionary()
        {
            // dict -> list 
            // 转换为 List<T>,T 的类型是 KeyValuePair<TKey, TValue>
            Dictionary<string, int> d = new Dictionary<string, int>();
            var l = d.ToList();

            List<KeyValuePair<string, int>> l2 = new List<KeyValuePair<string, int>>{
                new KeyValuePair<string,int>("a", 1),
                new KeyValuePair<string,int>("b", 2)
            };


            // list -> dict 两种转换方式

            // 1. 可指定 keySelector 和 valueSelector;完全自定义字典 key, value 的类型            
            Dictionary<string, int> d2 = l2.ToDictionary(entry => entry.Key, entry => entry.Value);
            // 2. 也可只指定 keySelector, value 为 entry 的值。
            Dictionary<float, KeyValuePair<string, int>> d3 = l2.ToDictionary(
                entry => (float)entry.Value);
        }
    }
}

[转载]文档在线预览:总体思路

mikel阅读(1142)

[转载]文档在线预览:总体思路 – I can being – 博客园.

近两年出现了许多以“经验交易”为核心的文档平台,如豆丁网、百度文库、星期八等网站。这些网站将文档(知识)存放在网站(平台)上,供用 户浏览、讨论、下载,配以良好的积分体系和金钱激励(运营),完美的协调好知识分享与知识传播之间的微妙关系。这样即有Web2.0的用户互动,也有 Web3.0的价值分配,对社会也是非常好的资源重用,是非常棒的一种运营模式。
从技术层面 讲,这类网站的创新主要有文档预览、知识商城和SNS三个块。今年初公司也决定在公司内部引入这种模式,以实现公司内部文档特别是售前方案的分享,很荣 幸,我被安排为此项目的技术经理,也专门研究了文档在线预览的技术。如今项目已经上线将近百天,也是时候整理一下思路,这篇博客主要就是分析一些文档在线 预览的技术细节,其实网上已经有很多类似的文章,但大多没有说得很清楚,也比较零乱,所以我想整理一个完整的文章来。文章内容将会涉及:总体思路、预览实现细节、缩略图实现、百度阅读器使用等。
文档预览即文档以flash的形式在网页上展示,所以要解决两个问题:以什么格式展示flash、文档如何转化为符合格式的flash
展示flash有两种方式,一种是直接生成好一个完整的flash展示出来,一种是用一个播放器来播放另外一个文档flash。第一种方式可以用 SWFTools的工具直接将pdf转化成一个整体的flash展示,但这种方式的flash较大,且不容易控制,故用得较少。第二种方式是重点,首先需 要了解的是一个开源的flexpaper播放器,它可以播放一帧一页的flash;在flexpaper的基础上,如果遇到大文档则会出现速度和性能的问题,这个时候需要像百度文库、豆丁一样修改flexpaper,让它支持一次仅读取指定页数的flash;如果文档安全级别较高,不允许下载查看,则需要给flexpaper加上加密解密算法;如果需要登录用户才能查看,则要让flexpaper有登录UI
转化文档为flash的思路有一条,但有多种实现方式。一般文档需要先转化为pdf,再从pdf转化为flash。转化为pdf的方法有很多,例如使用虚拟打印机、使用MicrosoftOffice的API、使用OpenOffice转化等,不过转化的过程中,可能由于文档有误、损坏、加密等原因造成转化失败。从pdf转化为flash就简单了许多,直接使用SWFTools的pdf2swf即可实现多种方式的转化。
下图是文档转化到swf的一个流程,其中type是文档的一个状态标识(0表示未处理过的文档,1表示已生成pdf,2表示已生成flash,-1表示不受支持的文档格式,-2表示转化为pdf失败,-3表示转化为flash失败)

[转载]高性能MMORPG通用服务端引擎设计之->基本概念篇

mikel阅读(887)

[转载]高性能MMORPG通用服务端引擎设计之->基本概念篇 – 懒人居 – Coding for fun – 博客园.

鉴于公司保密协议,本系列文章将不涉及具体的游戏细节以及实现。由于本人也是第一次参与此类引擎的设计,所以难免有所失误,如有异见欢迎业内人士讨论,发表本系列文章的目的不在于说教,重在分享以及讨论。
MMORPG 的服务端引擎是驱动整个游戏的总要部件,而且对于现在外挂满天飞的年代,服务端的地位变得愈发重要,很多游戏都将很多原来由客户端处理的逻辑交给了服务端 来处理,以避免各类外挂对游戏公平性造成的影响。要设计一款通用的且高性能的MMORPG服务引擎是一个非常艰巨的工作,总的来说,一款网游能够承载多少 人,能够实现什么功能,能够开展什么运营活动,都是跟有一款够不够强悍的服务端引擎有密切的关系,可以说服务端引擎就是游戏的心脏,如果设计不好,就会 “心率不齐”,“心肌梗塞”,然后不能支撑足够的在线人数,操作“卡”,最后死掉翘辫子。设计精良的引擎,比如WOW,EVE Online等,则给运营和策划留下来大量的空间,这样游戏的成功也就不存在“技术问题”了。
一般来说,当然是想一个游戏装的用户越多越好,当然 这里有很多现实上的制约,第一是运营上,游戏里总是老玩家等级更高、实力更强,由于游戏的竞争性,玩家都喜欢进新服,所以一组服务器总是在开服的时候开始 在线人数持续攀升,然后在某个点后就会下降并趋于稳定。其二是因为游戏中的场景不是无限大的,有固有的玩家密度限制,如果一个游戏屏幕上到处都塞满人,估 计你也不会觉得好玩。并且根据这两个特点就决定了,MMORPG的服务引擎需要有高性能,这样才能在开服的时候承载尽可能多的用户进入,并且要具备高度的 可伸缩性,在开服用户在线高峰的时候可以用比较多的服务器资源来拉动用户,在平稳运行后能够省出多余的服务器资源来挪给其他的服务器组。
从最简单的来说,MMORPG游戏基本上就是经典的C-S结构的系统,所以最简单的结构就是
Server
|
|

Client

这个时候Server端什么都要处理,就是忒累点,所以承载能力也就不用指望了,扩展能力就更不用想了,不过胜在简单,如果好好设计性能还是有保障 的。有个开源的C#开发的UO的服务引擎实现大家可以借鉴一下,http://www.runuo.com/。其实从本质上来说MMORPG的服务端和企 业应用没有差别,所以我们解决问题的方式也是很相似的,如果性能有问题,一台服务器无法解决问题,就用两台,属于叫分而治之的策略,所以要提高性能,我们 需要从系统的最慢的地方开始。如果有点经验的开发人员都知道,系统中最慢的就是数据库了。所以要提高系统的响应,我们一般是在用户的角色登录的时候直接将 角色的数据读进内存来处理,但是内存的数据不怎么保险,万一服务器当掉或者掉电了怎么办呢,这个问题就需要定时将用户的数据变更发给数据库了,这样就不存 在读写数据库的延迟了,当然掉电的时候在上一次保存后的数据还是会掉,这个时候就叫服务器回档,这种小几率事件一般我们不用特殊处理,一般游戏偶尔出现故 障回档的话基本都是对在线的用户赔点经验装备了事。以后架构还有可能扩张,而为了让你不必将SQL写得满世界都是,我们将数据库操作抽象成数据库服务,为 了多台服务器都可以一视同仁的使用,也也可以单独用一台服务器来作为数据库服务的主机,如下图:

DB-Service
|
Server
|
CLient

这张图看着很眼熟吧,恩,啥三层架构不就是这么画的嘛。囧 这个时候系统的压力就不在数据存储上了,于是压力到了游戏的逻辑上,现在游戏既要同时处 理大量的并发网络请求,且还要对游戏的逻辑进行运算,一边是高IO应用,一边是高CPU运算,都放在一块那就是一半火焰一半海水,不是烧死就是淹死了。高 网络IO并不需要很强的CPU运算性能,比如路由器,一台城域网的核心路由器负担了整个城市的出口网络路由,IO高得吓人,路由器其实也就是一台特殊的电 脑,但是这台核心路由器的CPU其实并不比我们的家用PC的CPU高,甚至有可能低一点。但是游戏的逻辑运算对CPU的消耗就是实打实的消耗了,假设游戏 有1000个玩家在线,这个时候每处理一个事件需要1ms,那么假设每个玩家每秒有4个事件需要处理,那么1000个玩家就把一颗4核CPU或者2颗双核 CPU的计算能力耗尽了,这里还是假设的理想情况,如果再加上NPC,怪物,物品之类的要处理,那就需要非常多的CPU资源,如果所有CPU资源都给了逻 辑运算,网络消息处理所需的CPU能力就不足了,虽然消耗低,但是总是消耗的,所以我们继续采取分而治之的办法来处理,我们把前端服务器和逻辑服务器分 开,前端服务器用来处理大量的用户链接和消息分发,而逻辑服务器用来处理游戏逻辑。由于游戏逻辑更消耗CPU,所以一个前端服务器可以带N台逻辑服务器, 所以结构改成了下图:

Logic-Service   Logic-Service    DB-Service
|                     |                       |
————————————-
|
Front Server
|
Client

我们可以继续将游戏逻辑进行分类,由于MMORPG的每一个玩家从经入游戏开始就是处于一个个的场景当中的,所以逻辑服务器也可以叫场景服务器 (地图服务器),有的游戏即使没有场景切换,其实也是分了很多场景的,只是采用了无缝拼接的技术让你觉得是没有分开的。玩家的逻辑就可以分为连续事件逻辑 和瞬时逻辑。连续事件逻辑是在场景中需要和其他用户发生反映的事件,也可以称之为场景事件,比如我攻击了一个怪,这一个事件需要通知场景里所有的玩家知 道,并且会影响怪接下来的行动。所谓的瞬时事件,就是只会影响玩家自身的状态且不需要通知其他玩家或者说是对场景产生影响的(当然如果对场景产生了影响势 必需要通知场景内其他玩家)。有的事件甚至会跨场景通知系统内所有用户(比如某玩家击杀了某著名BOSS,或者通知师父自己的徒弟在某处遭到了攻击[假如 要实现师徒系统的话])。玩家大部分的逻辑都是在场景内完成的,所以场景逻辑的实现非常的重要。在这个部分的运算涉及到多个对象间的互动,如果想用多线程 来提高并行度来提高性能其实反而会适得其反,因为要保证计算的数据安全避免脏读,在多线程的环境下就需要处理大量的锁,相信在游戏的业务逻辑里还需要处理 锁,防止死锁这里的处理会宁所有的程序员抓狂,对于这种高CPU运算的场景来说,大量的线程也会将宝贵的CPU时间浪费不少在线程切换上,所以一般来说游 戏的逻辑服务器都是单进程单线程的结构,通过一个大循环来驱动整个事件逻辑。那么你可能会问,如果有单进程单线程岂不是只能利用一颗CPU内核了么?当然 一个游戏也不可能只有一个场景嘛,我们可以在一台服务器上跑N个场景服务,处理N个场景的逻辑(根据经验来说,N=CPU内核数量性能最好)。所以你可以 看到为啥上图我不写Logic Server而是写的Logic Service了。
当玩家连接上Front Server后怎么知道要把数据发到那一个Logic Service呢?这里就需要场景管理服务了,根据我的想法,我想在场景管理服务里提供一个用户代理,用户代理知道用户在那个场景中,代理了用户登录场 景,离开场景的行为,以及帮助用户将数据转发到正确的场景服务上,所以结构图继续进化成下图:
Logic-Service   Logic-Service    DB-Service
|                     |                      |
————————————
|
Scene Manager
|

Front Server
|
Client
由 于Front Server的数据都由场景管理服务器转发到场景上,所以我们在前端可以部署多个Front Server,因为一个Front Server只有100M的带宽,当Front Server性能不足或者带宽不足的时候我们可以通过两个来搞定,而Scene Manager只通过用户代理来做包转发,所以承载能力相当的高。再次增强后系统如下图:
Logic-Service   Logic-Service    DB-Service
|                      |                     |
————————————
|
Scene Manager
|
—————-
|                   |
Front Server   Front Server
|                   |
Client         Client

考虑到Front Server有可能会存在CPU剩余的情况,所以也可以将一部分瞬时事件交给Front Server来处理,当然有一个公共的很耗时的瞬时逻辑需要被剥离出来,那就是登录的逻辑,登录的逻辑每一组服务器都一样,所以我们可以将N组服务器的登 录交给一个统一的登录服务器来处理,所以我们再次进化

Logic-Service   Logic-Service    DB-Service
|                     |                     |
———————————–
|
Scene Manager
|
————————————-
|                       |                      |
Front Server   Front Server     Login Server
|                      |
Client             Client

现在看起来大体上已经有点模样了,但是其实还可以根据不同的需求做一些细节上的调整,比如怪物的AI运算,如果仅仅是很简单的逻辑运算,其实就可 以直接在场景服务器的逻辑中处理了(其实有点像把怪物当作了场景的一部分)。如果需要很复杂的AI,就需要将怪物的AI拿到单独的进程里运算了,其实就是 把怪物当成一个特殊的玩家来对待,这种模式比较特殊,由于比较耗资源,一般都对大BOSS采用这种方式。
写了这么多也不知道是不是说明白道清楚 了,不过今天先说到此处打住,下一回我们从细节上来看这每一部分的具体设计,或许还有部分实现。如果在我下一篇写出来前有兴趣和我继续讨论的可以加MSN superpowerlee@hotmail.com或者Gtalk superpowerlee@gmail.com
感谢iiegg的刘洋以及王秋婷同学给我的大力支持,作为一个新人来说得到业界前辈的无私帮助真是非常幸运的事情。

本文为亚历山大同志独立思考之结果,有可能在最终结果可能于某些网络上已有资料不谋而合,皆因为相同产品设计理念相同,非抄袭之过。本文欢迎讨论,欢迎转载,如转载请注明出处,谢谢。

[转载]自定义asp.net mvc的WebFormViewEngine修改默认的目录结构

mikel阅读(975)

[转载]【小技巧】自定义asp.net mvc的WebFormViewEngine修改默认的目录结构 – liulun – 博客园.

先看一下我的解决方案的目录结构吧~~~

一:先把Controller程序提取出来

默认的情况是所有的****Controller.cs文件都会放在Web程序集下的一个叫Controllers的文件夹下

这样感觉有点不爽(你懂的…)

我们决定把所有的Controller程序放到一个自定义的应用程序集中去(上图中的mrlh.Admin.Controllers)

先把web程序集下的Global.asax.cs文件删掉

然后把Global.asax的标记代码改为如下:

<%@ Application Codebehind="mrlh.Admin.Controllers.App.MvcApplication" Inherits="mrlh.Admin.Controllers.App.MvcApplication" Language="C#" %>

这样应用程序启动时就会到我们自定义的应用程序集去执行相关的操作了

mrlh.Admin.Controllers.App.MvcApplication的相关代码如下

namespace mrlh.Admin.Controllers.App
{
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // 路由名称
"{controller}/{action}/{id}", // 带有参数的 URL
new { controller = "XiTong", action = "Index", id = UrlParameter.Optional } // 参数默认值
);
}
protected void Application_Start()
{
//以下两句为启用自定义的WebFormViewEngine
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MvcViewEngine());
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
}
}

这样做之后

所有的Controller程序就不用集中写到web程序集中去了,

就可以写在mrlh.Admin.Controllers这个程序集中了

二:改变View文件夹的目录结构

默认的情况是所有的****.aspx文件都放在web程序集中的Views目录下

这样感觉也有点不爽(你懂的…)

如果想改变aspx文件的目录结构,就必须自定义WebFormViewEngine了

细心的读者会看到在上面的代码中Application_Start方法里前面三句话

//以下两句为启用自定义的WebFormViewEngine
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MvcViewEngine());

这就是把自定义的 WebFormViewEngine添加到应用程序中去的方法

MvcViewEngine的代码如下

namespace mrlh.Admin.Controllers.App
{
public class MvcViewEngine : VirtualPathProviderViewEngine
{
public MvcViewEngine()
{
MasterLocationFormats = new[] {
"~/{1}View/{0}.master",
"~/SharedView/{0}.master"
};
AreaMasterLocationFormats = new[] {
"~/Areas/{2}/Views/{1}/{0}.master",
"~/Areas/{2}/Views/Shared/{0}.master",
};
ViewLocationFormats = new[] {
"~/{1}View/{0}.aspx",
"~/{1}View/{0}.ascx",
"~/SharedView/{0}.aspx",
"~/SharedView/{0}.ascx"
};
AreaViewLocationFormats = new[] {
"~/Areas/{2}/Views/{1}/{0}.aspx",
"~/Areas/{2}/Views/{1}/{0}.ascx",
"~/Areas/{2}/Views/Shared/{0}.aspx",
"~/Areas/{2}/Views/Shared/{0}.ascx",
};
PartialViewLocationFormats = ViewLocationFormats;
AreaPartialViewLocationFormats = AreaViewLocationFormats;
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
return new WebFormView(partialPath, null);
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
return new WebFormView(viewPath, masterPath);
}
}
}

这样做之后类似这样的请求

http://localhost:12232/YuanGong/YuanGong

都会在web程序集中找到YuanGongView/YuanGong.aspx

然后再呈现给“观众”

注意:

这里不能试图把每个文件夹名字中后面的”View”字样去掉,

因为ASP.NET MVC如果发现服务器的物理路径上存在相应的文件,将直接输出了

也就是请求是这样的http://localhost:12232/YuanGong/YuanGong

发现服务web目录下对应有此文件YuanGong/YuanGong.aspx

将直接输出

三:自定义目录结构的好处

我之所以这样做一个是为了感官上的舒服,毕竟自己的程序跟自己的媳妇一样

不但要从触觉上考虑,还要从视觉上考虑

另外还可以把多个web程序集的controller程序放在同一个程序集中方便代码的重用

(忽然觉得好像面向服务编程)

其三目录结构改变了,也方便权限的控制

demo:http://files.cnblogs.com/liulun/MRLH.rar

[转载]ASP.NET MVC 框架结构图

mikel阅读(997)

[转载]ASP.NET MVC 框架结构图 – 哲学驱动设计 – 博客园.

最近在学ASP.NET MVC,画了一些图,和大伙分享下:


Routing 组件

image

图1 独立的ASP.NET Routing组件


MVC-Controller

image

图2 Controller结构

image

图3 Controller中可用的ActionResult


MVC-View

image

图4 使用的抽象工厂模式的视图引擎

image

图5 视图模型

[转载]C#调用dephi的dll之详解-完整版_附有可下载Demo

mikel阅读(1152)

[转载]C#调用dephi的dll之详解-完整版_附有可下载Demo – elivn – 博客园.
C#调用Dephi接口方法,有两种解决办法:

一、将Dephi程序编译成一个COM组件,然后在C#里引用COM组件。

二、非托管调用Dephi的DLL文件。

这里我们主要讲解一下第二种方法,讲第二种方法之前首先讲解下DllImport。

DllImport是System.Runtime.InteropServices命名空间下的一个属性类,其功能是提供从非托管DLL导出的函数的必要调用信息。

DllImport属性应用于方法,要求最少要提供包含入口点的dll的名称。
DllImport的定义如下:

代码

1 [AttributeUsage(AttributeTargets.Method)]
2 public class DllImportAttribute: System.Attribute
3 {
4 public DllImportAttribute(string dllName) {…} //定位参数为dllName
5 public CallingConvention CallingConvention; //入口点调用约定
6 public CharSet CharSet; //入口点采用的字符接
7 public string EntryPoint; //入口点名称
8 public bool ExactSpelling; //是否必须与指示的入口点拼写完全一致,默认false
9 public bool PreserveSig; //方法的签名是被保留还是被转换
10 public bool SetLastError; //FindLastError方法的返回值保存在这里
11 public string Value { get {…} }
12 }
13

上面DLL的名字有时需要写上路径的如[DllImport(@”C:\OJ\Bin\Judge.dll”)]这样指定DLL的绝对路径就可以正常装载。

假如没有路径的话,DllImport会按照顺序自动去寻找的地方:
1、exe所在目录
2、System32目录
3、环境变量目录
所以只需要你把引用的DLL 拷贝到这三个目录下, 就可以不用写路径了。

说明:
1、DllImport只能放置在方法声明上。
2、DllImport具有单个定位参数:指定包含被导入方法的 dll 名称的 dllName 参数。
3、DllImport具有五个命名参数:
a、CallingConvention 参数指示入口点的调用约定。如果未指定 CallingConvention,则使用默认值 CallingConvention.Winapi。
b、CharSet 参数指示用在入口点中的字符集。如果未指定 CharSet,则使用默认值 CharSet.Auto。
c、EntryPoint 参数给出 dll 中入口点的名称。如果未指定 EntryPoint,则使用方法本身的名称。
d、ExactSpelling 参数指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配。如果未指定 ExactSpelling,则使用默认值 false。
e、PreserveSig 参数指示方法的签名应当被保留还是被转换。当签名被转换时,它被转换为一个具有 HRESULT返回值和该返回值的一个名为 retval 的附加输出参数的签名。如果未指定 PreserveSig,则使用默认值 true。
f、SetLastError 参数指示方法是否保留 Win32″上一错误”。如果未指定 SetLastError,则使用默认值 false。
4、它是一次性属性类。
5、此外,用 DllImport 属性修饰的方法必须具有 extern 修饰符。

下面讲解下如何调用:

用DllImport来调用的  一般是用非托管的。
具体形式如下:1.[DllImport(“WZFSE.dll”, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]。

其中第一个参数是指要引用DLL的名字, 这个名字应该是个常量(否则会出错)。
要想在自己C#页面中引用,那就得在页面中申明这个函数。

下面紧接着他的申明函数:
2.public static extern void InitDll(IntPtr handle, bool methodAddress);(Dephi里怎么定义的函数在C#这里就要怎么定义:即Dephi的申明函数转换成C#的声明函数)。
–申明一个函数就要引用下他的DLL 如1和2是紧密连在一起的。即再写一个函数就相应的应用起对应的DLL。

下面是参数的引用:即Delphi的类型向C#的转换。

第一个参数类型:IntPtr这个类型可以申明为其他语言的句柄,指针等。
若要实现其他语言类似C++的函数指针形式, 这时我们考虑用C#的委托来实现。

下面说一下:如何将Dephi的窗体显示在自己的页面中(且不能显示dephi窗体的标题栏,实现无缝的结合)。

将dephi的窗体签入到自己的C#系统里 还有一点比较重要,我们是调用dephi的窗体,此时显示在我们C#窗体中会有dephi的窗体,

这时我们怎么办呢,  怎么去除dephi中的窗体呢?  这时我们就需要用API函数了。 因为WINDOWS API是一种比较底层的语言,可以通过它进行操作。

在C#中是这么引用的: [DllImport(“user32.dll”, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern void MoveWindow(IntPtr handler, int x, int y, int width, int height, bool repaint);

下面插入一个类,这里面包含了怎么引用dephi的dll 以及怎么申明:

代码

1 public class CompliancePlatDLL
2 {
3 public static string strPath = “”;
4 /// <summary>
5 /// 初始化
6 /// </summary>
7 /// <param name=”handle”></param>
8 /// <param name=”methodAddress”></param>
9 [DllImport(WZFSE.dll, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
10 public static extern void InitDll(IntPtr handle, bool methodAddress);
11 /// <summary>
12 /// 加载相应的服务
13 /// </summary>
14 /// <param name=”str”></param>
15 /// <param name=”str2″></param>
16 /// <param name=”i”></param>
17 /// <returns></returns>
18 [DllImport(WZFSE.dll, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
19 public static extern IntPtr wzLoadModule(string str, string str2, int i);
20 /// <summary>
21 /// 去除相应的服务
22 /// </summary>
23 /// <param name=”handle”></param>
24 /// <returns></returns>
25 [DllImport(WZFSE.dll, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
26 public static extern bool wzUnloadModule(IntPtr handle);
27
28 #region API函数
29 /// <summary>
30 /// API函数 设置主辅窗体
31 /// </summary>
32 /// <param name=”child”></param>
33 /// <param name=”parent”></param>
34 [DllImport(user32.dll, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
35 public static extern void SetParent(IntPtr child, IntPtr parent);
36 /// <summary>
37 /// API函数 移动窗体
38 /// </summary>
39 /// <param name=”handler”></param>
40 /// <param name=”x”></param>
41 /// <param name=”y”></param>
42 /// <param name=”width”></param>
43 /// <param name=”height”></param>
44 /// <param name=”repaint”></param>
45 [DllImport(user32.dll, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
46 public static extern void MoveWindow(IntPtr handler, int x, int y, int width, int height, bool repaint);
47
48 [DllImport(user32.dll, EntryPoint = GetWindowLong)]
49 public static extern long GetWindowLong(IntPtr hwnd, int nIndex);
50 /// <summary>
51 /// API函数 去除窗体的标题栏
52 /// </summary>
53 /// <param name=”hwnd”></param>
54 /// <param name=”nIndex”></param>
55 /// <param name=”dwNewLong”></param>
56 /// <returns></returns>
57 [DllImport(user32.dll, EntryPoint = SetWindowLong)]
58 public static extern long SetWindowLong(IntPtr hwnd, int nIndex, long dwNewLong);
59 public const int GWL_EXSTYLE = 16;
60 public const int WS_EX_TRANSPARENT = 0x20;
61 public const int WS_EX_LAYERED = 0x80000;
62 public const int LWA_ALPHA = 2;
63 public const int WS_CAPTION = 0xC00000;
64 #endregion
65 }

其中API中的SetWindowLong这个方法是可以实现去除窗体的标题栏的,  具体调用SetWindowLong(common.p, GWL_EXSTYLE, GetWindowLong(handle, GWL_EXSTYLE) & (~WS_CAPTION));

但一般完整利用API函数的调用是这样的

代码

1 decallback de1 = new decallback(iscallback);//利用委托
2 InitDll(this.Handle, de1(this.Handle));//初始化
3 IntPtr p = wzLoadModule(DoRiskSetup, “”, 0);//取得句柄
4 if (p != (IntPtr)0)//判断该句柄不是弹出窗体时
5 {
6 //去除dephi窗体的标题栏
7 SetParent(p, panel1.Handle);
8 SetWindowLong(p, GWL_EXSTYLE, GetWindowLong(p, GWL_EXSTYLE) & (~WS_CAPTION));
9 MoveWindow(p, 0, 0, panel1.ClientSize.Width, panel1.ClientSize.Height, false);
10 }

SetWindowLong(IntPtr handle, int t,long l) 第一个参数为句柄,是你调的dephi窗体的句柄,第二个参数为整型,在dephi用常量GWL_EXSTYLE表示,表示要显示的样式,在C#中翻译过 来的他值为(-16),而第三个函则为长整型和第二个参数一起表示要去除第一个参数句柄窗体的标题栏在dephi中表示 为:GetWindowLong(handle,GWL_EXSTYLE) and (not WS_CAPTION) 在C#中则翻译为:GetWindowLong(handle,-16)&(~0xC00000),handle是指要调用的dephi窗体的句 柄,GetWindowLong这个函数是获得该窗体的相关信息。大体上是这个用法,如有不懂大家可以提出来 共同探讨。

一般类型对应如下:

Dephi–>C#

intger –>int

longint –>long

pchar –>string

THandle –>IntPtr

上图为C#窗体调用的dephi的情况。

注:上面的dll的名称只是个例子 具体还要看你要引用哪个dll  API中的函数在C#中是这样引用的

表达能力有限 希望对你们有帮助··具体不懂可邮箱联系: elivn@vip.qq.com

调Delphi的DLL.rar 一个简单的调用Demo,  希望对大家有用。由于自己使用的地方文件太大就用了同事的一个简单的调用Dephi的Demo。

如有转载 请注明出处!

[转载]简单实用的防止多次提交辅助类

mikel阅读(1116)

[转载]简单实用的防止多次提交辅助类 – 破狼 – 博客园.

一:  开题

这篇只是一个简单的应用技巧,高手请跳过,别拍砖,打击我这个有激情的菜鸟。在我们的web项目中经常会遇见由于网络原为等问题,而导致在页面提高后,服 务器还没有来得及返回的时候,我们的用户可能在此点击按钮使的数据多次的提交。防止这个行为很简单,我们一般经常是在按钮点击后使其禁用 disabled=true。我是一个很懒的人(生活中并不懒,只是写Code比较懒,我的目标是:少写Code,基于配置而不写Code是最好的3]6GJ(EWN[K2P[Z6B`6B`2H)。 所以就有了这个简单的辅助类:我的思路是在page的PreRender时间中注册提交前执行的脚本全部提交按钮的disabled=true(  page.ClientScript.RegisterOnSubmitStatement()。)等待服务器返回时会更具返回浏览器会重绘,所以我们的 设置此时已经无用了。呵呵就这面简单。但是为不少写代码,那些了一个辅助类DoubleSubmitPrevent,提供的几种方式自动按照按钮,或者是 手动添加按钮(取决于IsAutoFind),自动查找的起点默认为page,但是为了效率你可以自己设置BaseContrlForFind,关于需要 禁止的按钮的判断为IsPreventControl你可以自己定义覆盖默认的,默认为:

代码

private System.Predicate<System.Web.UI.Control> isPreventControl = t => (t is System.Web.UI.WebControls.Button) ||
(t
is System.Web.UI.WebControls.LinkButton) ||
(t
is System.Web.UI.WebControls.ImageButton) ||
(t
is System.Web.UI.HtmlControls.HtmlButton) ||
//(t is System.Web.UI.HtmlControls.HtmlLink) ||
(t is System.Web.UI.HtmlControls.HtmlInputButton) ||
(t
is System.Web.UI.HtmlControls.HtmlInputSubmit);

如果你还是觉得效率不好那么,你就可以自己Add或者AddRange,同时包括了Remove,Insert等方法,这一系列方法都支持链式操作 (这是第一次使用JQuery的时候给我的最大触动)。例 如:dsp.Add(Button1).Add(Button2).Add(Button3).Add(LinkButton1).Add(LinkButton2) =dsp.AddRange(Button1,Button2,Button3,LinkButton1,LinkButton2);包括的多个重载;

二: Code部分

说了这么多还是直接上代码:

代码

namespace Wolf.Utils
{
public class DoubleSubmitPrevent
{
private System.Collections.Generic.List<string> _clientIDList = null;
private const string DOUBLE_SUBMIT_PREVENT_STR = B3F6F682-F404-4519-9F30-79876E5A5C9A_WOLF_DOUBLESUBMITPREVENT_391B8D4F-757E-4005-8262-062652D8BAC6;
private bool isAutoFind = false;
#region judje  Prevent Control?
private System.Predicate<System.Web.UI.Control> isPreventControl = t => (t is System.Web.UI.WebControls.Button) ||
(t
is System.Web.UI.WebControls.LinkButton) ||
(t
is System.Web.UI.WebControls.ImageButton) ||
(t
is System.Web.UI.HtmlControls.HtmlButton) ||
//(t is System.Web.UI.HtmlControls.HtmlLink) ||
(t is System.Web.UI.HtmlControls.HtmlInputButton) ||
(t
is System.Web.UI.HtmlControls.HtmlInputSubmit);
#endregion
private System.Web.UI.Control baseContrlForFind = null;

/// <summary>
/// Auto Find will satrt with this Control;Default this Page .
/// </summary>
public System.Web.UI.Control BaseContrlForFind
{
get { return baseContrlForFind; }
set { baseContrlForFind = value; }
}

/// <summary>
/// judje the Contrl that be prevented;
/// </summary>
public System.Predicate<System.Web.UI.Control> IsPreventControl
{
get { return isPreventControl; }
set { isPreventControl = value; }
}
/// <summary>
/// Auto Find the Control that be prevented ?
/// </summary>
public bool IsAutoFind
{
get { return isAutoFind; }
set { isAutoFind = value; }
}

public DoubleSubmitPrevent(System.Web.UI.Page page)
{
_clientIDList
= new System.Collections.Generic.List<string>();
baseContrlForFind
= page;
page.PreRender
+= new System.EventHandler(DoubleSubmitPreventPagePreRenderHick);
}

public DoubleSubmitPrevent Add(string clientID)
{
_clientIDList.Add(clientID);
return this;
}
public DoubleSubmitPrevent Add(System.Web.UI.Control ctr)
{
_clientIDList.Add(ctr.ClientID);
return this;
}

public DoubleSubmitPrevent AddRange(params string[] clientIDs)
{
_clientIDList.AddRange(clientIDs);
return this;
}

public DoubleSubmitPrevent AddRange(params System.Web.UI.Control[] ctrs)
{
foreach (var item in ctrs)
{
Add(item);
}
return this;
}

public DoubleSubmitPrevent Remove(string clientID)
{
_clientIDList.Remove(clientID);
return this;
}

public DoubleSubmitPrevent Remove(System.Web.UI.Control ctr)
{
_clientIDList.Remove(ctr.ClientID);
return this;
}

public bool Exists(string clientID)
{
return _clientIDList.Exists(t => t.Equals(clientID));
}

public bool Exists(System.Web.UI.Control ctr)
{
return _clientIDList.Exists(t => t.Equals(ctr.ClientID));
}

protected virtual void DoubleSubmitPreventPagePreRenderHick(object sender, System.EventArgs e)
{
System.Web.UI.Page page
= sender as System.Web.UI.Page;
if (page != null)
{

if (isAutoFind)
{
#region Find Action
System.Action
<System.Collections.Generic.List<string>, System.Web.UI.Control> action = null;
action
= (list, ctr) =>
{
if (ctr != null)
{
if (isPreventControl(ctr))
{
list.Add(ctr.ClientID);
}
foreach (System.Web.UI.Control item in ctr.Controls)
{
action(list, item);
}
}

};
#endregion
action(_clientIDList, baseContrlForFind);

}

System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (var item in _clientIDList)
{
sb.Append(
string.Format( document.getElementById(\{0}\).disabled=true;, item));
}
page.ClientScript.RegisterOnSubmitStatement(
this.GetType(), DOUBLE_SUBMIT_PREVENT_STR, sb.ToString());
}
}
}
}

三: 测试:

为了模拟延时,我在后台加了睡眠:

代码

protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
System.Threading.Thread.Sleep(
1000 * 5);
TextBox1.Text
= DateTime.Now.ToString();
Button3.Enabled
= false;
}
Wolf.Utils.DoubleSubmitPrevent dsp
= new Wolf.Utils.DoubleSubmitPrevent(this) { IsAutoFind = true, BaseContrlForFind = this.form1 };
//dsp.Add(Button1).Add(Button2).Add(Button3).Add(LinkButton1).Add(LinkButton2);

}

前台html(乱托乱扔的,看来是比较懒8{U`QQB5X27@C_FO](KQ(4G):

代码

<form id=form1 runat=server>
<asp:TextBox ID=TextBox1 runat=server></asp:TextBox>
<asp:Button ID=Button1 runat=server Text=Button Enabled=false />
<asp:Button ID=Button2 runat=server Text=Button />
<asp:Button ID=Button3 runat=server Text=Button />
<asp:LinkButton ID=LinkButton1 runat=server>LinkButton</asp:LinkButton><asp:LinkButton
ID
=LinkButton2 runat=server>LinkButton</asp:LinkButton>
</form>

效果:

F]KRP2ZDF95F1FSZ)L57(NN

如果你又更好的方案,也希望能给我分享,请大家多多指教。

[转载]flash wmode="window" 时的遮挡问题

mikel阅读(1046)

[转载]flash wmode=”window” 时的遮挡问题. – Franky – 博客园.

在本文开始前 , 我先引入,摸同学的文档. 来说明一些问题.然后我在此基础上,会做一些扩展说明.

基于以上的认识,我们开始接下来的话题…
我们所要解决的是这样一种需求: 当我们 现在有一个很大滴 flash 在页面上,且wmode 必须为window的前提下…如何使我们的一些元素不被 flash遮挡的呢?

遗憾的是,我所能给出的答案是 . 并不完美.我仍然无法搞定 opera 和 safari 两款浏览器. 那么此文 希望可以起到抛砖引玉的作用吧.
其实答案很简单. 在展示元素下面、flash上面放一个iframe.
一个最佳实现方式是:
<iframe src=”about:blank” width=”300″ height=”200″ frameBorder=”0″ style=”z-index:-1;position:absolute;top:0;left:0;border:0″></iframe>
把这样的一个iframe 按照你喜欢的方式 放入元素中.(应该是该元素直系子节点.)其中 width height 为元素宽高. 重要属性z-index:-1.是我们的救星.
当然,最后别忘了加个透明度 0 ..否则ie下很郁闷.
好吧中心思想就是这个.但是,这个办法并不是所有浏览器都有效. 并且,各个浏览器总会有这样或那样的bug存在:
严重问题:
Safari : 无效.
Opera : 无效.
FireFox 3.6 及 4.0 demo : 无效.
FireFox 3.5 及之前版本 . 元素 position : fixed 以外的值. 无效. (即必须当节点的position:fixed时,才ok )

幸运的是对于FireFox3.6 及4.0 demo 我们已经无需借助iframe来修复.只需要给元素简单设置一个background 非 transparent 的值即可.
要注意的是,如果background 是一个image 那么,如果image 有透明部分,则任然会有问题.
FireFox 3.6 及 4.0 demo : 当使用background 修正时,如果这个修正仅针对元素内部的表格元素的 空td 则无效.(解决办法给td : display:block,或想办法 让td具备一个有效的宽高).

对于 FireFox 3.5 及之前版本,首先我建议放弃修复, 如果非要修复.则只好使用position:fixed,再配合中间的iframe,然后通过一系列js 修补其行为.让他看起来是正常的.

一些小问题:
IE6-IE9demo : 在flash与当前窗口上其他元素 切换焦点时, 元素会被flash遮挡.
IE7: 当 元素为 position:fixed时,滚动条滚动后.元素会被flash遮挡.
搜狗高速浏览器 2.1及之前的版本,webkit内核下: 当元素位置发生改变时. 会保留一个残影.(残影数一般只有一个,由于中间的iframe造成)

以上小问题.都可以通过触发Render Tree 全局 Reflow 修复.  除了QQ
考虑下面的代码:
var border = document.body.style.border ;

document.body.style.border = border == ‘solid 1px #000’  ?  ‘solid 1px #001’ : ‘solid 1px #000’ ;

document.body.offsetWidth; //强制浏览器flush当前的reflow队列.
document.body.style.border = border; //恢复border 原始值.

border 属性和值是随意的.只要你能引起全局的reflow 并且视觉上无影响.如何做都是可以的.. 比如ie下 可以用.body.style.zoom.
你甚至可以不实用offsetWidth,在1、0之间切换 zoom ,就可以直接造成reflow…  读取body.offsetWidth.可以绕过.浏览器对reflow队列的优化.


棘手的小问题:
QQ5  浏览器   webkit 内核下: 当元素位置发生改变时,产生残影造成花屏的现象.
此问题,全局reflow可以改善花屏效果.但连续移动中.视觉上更多的感觉是.元素被flash遮盖住了.直到元素停止移动.

搜狗高速浏览器 2.1及之前的版本,webkit内核下: 当元素所处 平面位置在flash外边时,而此时元素内部某子元素通过定位调整. 与flash 在平面上有交集时,交集部分会被flash遮盖.
此问题.需要修改元素 DOM结构来解决.暂时也无甚好的方法.

所有使用. chromium开源项目的 webkit内核的浏览器如:Chrome全系,maxthon3、搜狗高速浏览器、QQ5浏览器、360高速浏览器.下
使用iframe修复遮盖后. 动态修改 元素.style.clip 时. 由于元素可视区域变化.而造成的 iframe 残留阴影问题(此阴影与flash下面的背景同色).
应避免使用clip属性. 以避免此bug的出现.


好了 到了结束的时候了..

列出毛病最少的几个浏览器 也就是基本不需要使用 reflow的浏览器
chrome  maxthon3 搜狗高速浏览器2.2 FF3.6 +  以及使用比较新的chromium 开源项目所提供内核的浏览器 比如 360 高速浏览器 以及 等等 所谓高速浏览器的 国产山寨货们.

其中比较难搞的浏览器是搜狗2.2 和之前版本的 webkit判断.. 当然userAgent是有区别. 我仍然给出一个基于特性的检测方法:

var win = window,
isWebkit = !!+’\v1′ && !win.XDomainRequest && !navigator.taintEnabled;
if(isWebkit && !!win.external && ‘StartPageCall’ in external && !(‘localdb’ in external)){
//这里是你需要修复的搜狗高速浏览器webkit内核下 版本小于2.2的 浏览器 需要的逻辑.
}

好吧,代码很悲剧.我不得不承认这一点.

[转载]庖丁解ASP.NET MVC内部运行流程

mikel阅读(953)

[转载]庖丁解ASP.NET MVC内部运行流程 – Lipu falls in .Net – 博客园.

跟大家分享两张ASP.MVC的内部运行流程图,作者都是Steve Sanderson,上面这张是07年MVC还未正式发布之前做成的流程图,虽然较老但是放到今天大部分仍然基本适用(注意:图中有些部分已经过期但是因为比较详细全面,也贴上来了)。下面那张是09年的,贴上来的理由是图中详细的表出MVC框架里哪些部分是可以被拓展(extend)的, 比如说你可以用Cusotom route handler, Custom Handler 等等。

基本上讲,一个MVC项目启动时,包括下面5个步骤:

1. 启动:一个MVC的项目启动的时候,首先从Global.asax.cs里面的Application_Start()开始。在 Application_Start()里面定义routes, IoC container, ModelBinder, 等等需要在启动时配置好的部分;

2. 路径(routes):MvcHandler处理所有的请求 e.g. http://example.com/home/index,在这个环节的最后一步IHttpHandler的ProcessRequest方法被调用;

3. 生成controller: 在调用ProcessRequest方式时,DefaultControllerFactory按照进来的请求生成controller对象,e.g. HomeController. 之后controller对象调用Execute()方法;

4. 找到并调用controller action:controller在调用Execute()方法时,依靠ControllerActionInvoker找到相应的action,并调 用该action, e.g. 调用HomeController里面的index()方法;

5. 生成界面(render view): 最后controller返回ActionResult,由View Engine生成界面;

Creative Commons License

[转载]与VisualStudio集成的若干种代码生成解决方案

mikel阅读(1295)

[转载]与VS集成的若干种代码生成解决方案[博文汇总(共8篇)] – Artech – 博客园.

前一阵子写了不少关于代码生成相关的文章,介绍了一些如何通过VS自动生成代码的解决方案,比如CodeDOM、T4以及ASP.NET的BuildProvider等。现在将它们作一个汇总,给广大读者作一个参考。

[第1篇] 通过CodeDOM定义生成代码的结构

我 不知道大家对CodeDOM的代码生成机制是否熟悉,但是有一点可以确定:如果你使用过Visual Studio,你就应该体验过它带给我们在编程上的便利。随便列举三种典型的代码生成的场景:在创建强类型DataSet的时候,VS会自动根据 Schema生成相应的C#或者VB.NET代码;当我们编辑Resource文件的时候,相应的的后台代码也会自动生成;当我们通过添加Web Reference调用Web Service或者WCF Service的时候,VS会自动生成服务代理的代码和相应的配置。总的来说,通过和VS集成的动态代码生成工具使我们可以“强类型”的方式进行编程,进 而提供我们的效率并减低错误的几率。

CodeDOM 提供了表示许多常见的源代码元素类型的类型。您可以设计一个生成源代码模型的程序,使用CodeDOM 元素构成一个对象图。而这个对象图包含C#或者VB.NET代码包含的基本元素:命名空间、类型、类型成员(方法、属性、构造函数、事件等),并且包括方 法实现的具体语句(Statement)。也就是说它的结构就是对一个具体.vb或者.cs文件代码的反映。在这里我不会具体介绍CodeDOM体系结 构……[阅读全文]

[第2篇] 通过Visual Studio的Custom Tool定义代码生成器

在《前篇》中我们已经通过CodeDOM的形式定义了将要生成的代码结构,而这个CodeDOM对象就是CodeCompileUnitCodeCompileUnit本身是与编程语言无关的,我们可以利用基于某种编程语言(VB.NET或者C#)的CodeDomProviderCodeCompileUnit对 象转换成具体的代码文本。为了让我们的VS自动地为我们生成代码,我们需要以Custom Tool的形式编写相应的代码生成器。我们编写的代码生成器最终通过COM组件的形式对外提供服务,所以其中涉及到COM组件的注册。为了实现同VS的集 成,还涉及到相应注册表设置……[阅读全文]

[第3篇] 不同于CodeDOM的代码生成机制——T4

前 面两篇介绍了如何通过CodeDOM+Custom Tool的代码生成方式实现了代码的自动生成。实际上,我们最常用的代码生成当时不是CodeDOM,而是T4,这是一个更为强大,并且适用范围更广的代 码生成技术。T4是对“Text Template Transformation Toolkit”(4个T)的简称。T4直接包含在VS2008和VS2010中,是一个基于文本文件转换的工具包。T4的核心是一个基于“文本模板”的 转换引擎,我们可以通过它生成一切类型的文本型文件,比如我们常用的代码文件类型包括:C#、VB.NET、T-SQL、XML甚至是配置文件等。

对 于需要通过T4来进行代码生成工作的我们来说,需要做的仅仅是根据转换源(Transformation Source),比如数据表、XML等(由于例子简单,HelloWord模板没有输入源)和目标文本(比如最终需要的C#或者T-SQL代码等)定义相 应的模板。T4模板作用就相当于进行XML转化过程中使用的XSLT。

T4模板的定义非常简单,整个模板的内容包括两种形式:静态形式 和动态动态。前者就是直接写在模板中作为原样输出的文本,后者是基于某种语言编写代码,T4引擎会动态执行它们。这和我们通过内联的方式编写的 ASP.NET页面很相似:HTML是静态的,以C#或者VB.NET代码便写的动态执行的代码通过相应的标签内嵌其中。[阅读全文]

[第4篇] 通过T4模板实现单文件的代码生成

在《前一篇》 中,我对T4模板的组成结构、语法,以及T4引擎的工作原理进行了大体的介绍,并且编写了一个T4模板实现了如何将一个XML转变成C#代码。为了让由此 需求的读者对T4有更深的了解,我们通过T4来做一些更加实际的事情——SQL Generator。在这里,我们可以通过SQL Generator为某个数据表自动生成进行插入、修改和删除的存储过程……[阅读全文]

[第5篇] 通过T4模板实现多文件的代码生成

在《前一篇》中我们通过T4模板为我们指定的数据表成功生成了我们需要的用于添加、修改和删除操作的存储过程。但是这是一种基于单个文件的解决方案,即我们必须为每一个生成的存储过程建立一个模板。如果我们提供一种基于多文件的代码生成方式,将会为编程人员带来极大的便利。借助于T4 ToolBox这个开源工具箱,多文件的SQL Generator的实现变得异常简单。[阅读全文]

[第6篇] 解决T4模板的程序集引用的五种方案

如 果你的T4模板需要调用一个自定义的类型,并且该类型定义在某个非系统程序集中,你就需要通过T4<#@ assembly…#>指令引用该程序集。在VS 2008环境下,你只需要为当前项目添加相应的程序集引用,并且通过<@ assembly…#>指令的name属性指定程序集(Dll)的文件名即可。但是这种方式对于VS 2010则行不通,因为T4引擎在解析和编译模板的时候并不会从项目引用列表中去定位目标程序集。本篇文章为你介绍在VS2010下5种不同的程序集引用 的方式……[ 阅读全文]

[第7篇] 编写T4模板进行代码生成无法避免的两个话题:”Assembly Locking”&”Debug”

出 于提高性能考虑,T4引擎在进行基于代码生成的模板转换(Template Transformation)的时候,会始终重用同一个AppDomain。由于该AppDomain不会自动卸载,这就会导致该AppDomain始 终锁定所有被它加载的程序集。如果我们需要释放程序集,我们不得不重启VS。但是,对于T4模板的开发调试阶段,这种通过重新启动VS的方式去释放程序集 以确保我们的项目能够成功编译是不能接受的。那么,是否有一种解决方案既能够确保T4引擎能够进行正常的模板转换,又能避免它强行锁定引用程序集呢?

VS和一些T4编辑器虽然给了基本的智能感知支持,但是在绝大部分我们相当于在编写纯文本的脚本,所以对于一些比较复杂的模板转换逻辑,我们需要通过Debug的方式去发现一些无法避免的问题……[阅读全文]

[第8篇] 通过自定义BuildProvider为ASP.NET提供代码生成

对 于ASP.NET应用的开发者来说,你可能不知道什么是BuildProvider,但是你几乎无时无刻不在使用它所带来的代码生成机制。当你创建一 个.aspx文件的时候,为什么会自动创建对应源代码?当你在该.aspx页面中以XML的方式添加一个按钮,源代码中为什么会自动添加一个同名的属性。 实际上,ASP.NET就是通过一个特殊的BuildProvider实现了将.aspx文件内容转换成相应的源代码,这个特殊的.aspx文件就 是:PageBuildProvider。基于不同的文件类型,ASP.NET会采用不同的BuildProvider进行源代码的生成。比如 UserControlBuildProvider和MasterPageBuildProvider分别实现了基于用户控件文件(.ascx)和母板页 (.master)的源代码生成……[阅读全文]