见到好多人在网上问起在.NET 1.1下如何实现类似.NET 2.0中的WebResource.axd,做了一下,以下是实现代码:
1
using System;2
using System.Collections;3
using System.Globalization;4
using System.IO;5
using System.Reflection;6
using System.Security.Permissions;7
using System.Text;8
using System.Text.RegularExpressions;9
using System.Web;10
using System.Web.Configuration;11
using System.Web.UI;12
using System.Web.Util;13

14
namespace XCtrlLib.WebCtrl15


{16

/**//// <summary>17
/// HttpWebResourceHandler 的摘要说明。18
/// </summary>19
public class HttpWebResourceHandler : IHttpHandler20

{21
// Fields22
private static IDictionary _assemblyInfoCache = Hashtable.Synchronized(new Hashtable());23
private static IDictionary _typeAssemblyCache = Hashtable.Synchronized(new Hashtable());24
private static IDictionary _urlCache = Hashtable.Synchronized(new Hashtable());25
private static IDictionary _webResourceCache = Hashtable.Synchronized(new Hashtable());26
//private static readonly Regex webResourceRegex = new WebResourceRegex();27
private static readonly Regex webResourceRegex = new Regex("",RegexOptions.CultureInvariant);28

29

/**//// <summary>30
/// Implement from IHttphanders31
/// </summary>32
public bool IsReusable33

{34

get
{ return true; }35
}36

37
public HttpWebResourceHandler()38

{39
}40

41
void IHttpHandler.ProcessRequest(HttpContext context)42

{43
//WebResource.axd有两个参数,一个是hash,标记要读取哪个资源;一个是timestamp,标记dll最后一次编译生成的时间44
//<script src="WebResource.axd?d=pXCtrlLib|XCtrlLib.WebCtrl.Res.XScript.js&t=633196542000000000" type="text/javascript"></script>45

46
context.Response.Clear();47
string resStringEncrypted = context.Request.QueryString["d"];//pXCtrlLib|XCtrlLib.WebCtrl.Res.XScript.js48
if (StringUtil.IsNullOrEmpty(resStringEncrypted))49

{50
throw new HttpException(404, "This is an invalid webresource request.");51
}52

53
//string resString = Page.DecryptString(resStringEncrypted);54
string resString = Utils.DecryptString(resStringEncrypted);//解密55
//string resString = resStringEncrypted;56
int length = resString.IndexOf('|');57
string resString1 = resString.Substring(0, length);//pXCtrlLib58
if (StringUtil.IsNullOrEmpty(resString1))59

{60
throw new HttpException(404, "Assembly " + resString1 + " not found.");61
}62

63
string webResource = resString.Substring(length + 1);//XCtrlLib.WebCtrl.Res.XScript.js64
if (StringUtil.IsNullOrEmpty(webResource))65

{66
throw new HttpException(404, "Resource " + webResource + " not found in assembly.");67
}68

69
//得到程序集70
char chAssemblyType = resString1[0];//p71
string strAssemblyName = resString1.Substring(1);//XCtrlLib72
Assembly assembly = null;73
switch (chAssemblyType)74

{75
case 's':76
assembly = typeof(HttpWebResourceHandler).Assembly;77
break;78

79
case 'p':80
assembly = Assembly.Load(strAssemblyName);81
break;82

83
case 'f':84

{85

string[] textArray = strAssemblyName.Split(new char[]
{ ',' });86
if (textArray.Length != 4)87

{88
throw new HttpException(404, "This is an invalid webresource request.");89
}90
AssemblyName assemblyRef = new AssemblyName();91
assemblyRef.Name = textArray[0];92
assemblyRef.Version = new Version(textArray[1]);93
string name = textArray[2];94
if (name.Length > 0)95

{96
assemblyRef.CultureInfo = new CultureInfo(name);97
}98
else99

{100
assemblyRef.CultureInfo = CultureInfo.InvariantCulture;101
}102
string text6 = textArray[3];103
byte[] publicKeyToken = new byte[text6.Length / 2];104
for (int i = 0; i < publicKeyToken.Length; i++)105

{106
publicKeyToken[i] = byte.Parse(text6.Substring(i * 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);107
}108
assemblyRef.SetPublicKeyToken(publicKeyToken);109
assembly = Assembly.Load(assemblyRef);110
break;111
}112
default:113
throw new HttpException(404, "This is an invalid webresource request.");114
}115

116
//得到程序集中的资源117
bool isValidRequest = false;118
string contentType = string.Empty;119
bool performSubstitution = false;120
if (assembly != null)121

{122
int num3 = HashCodeCombiner.CombineHashCodes(assembly.GetHashCode(), webResource.GetHashCode());123
Triplet triplet = (Triplet) _webResourceCache[num3];124
if (triplet != null)125

{126
isValidRequest = (bool) triplet.First;127
contentType = (string) triplet.Second;128
performSubstitution = (bool) triplet.Third;129
}130
else131

{132
object[] customAttributes = assembly.GetCustomAttributes(false);133
for (int j = 0; j < customAttributes.Length; j++)134

{135
WebResourceAttribute attribute = customAttributes[j] as WebResourceAttribute;136
//if ((attribute != null) && (string.Compare(attribute.WebResource, webResource, StringComparison.Ordinal) == 0))137
if ((attribute != null) && (string.CompareOrdinal(attribute.WebResource, webResource) == 0))138

{139
webResource = attribute.WebResource;140
isValidRequest = true;141
contentType = attribute.ContentType;142
performSubstitution = attribute.PerformSubstitution;143
break;144
}145
}146
Triplet triplet2 = new Triplet();147
triplet2.First = isValidRequest;148
triplet2.Second = contentType;149
triplet2.Third = performSubstitution;150
_webResourceCache[num3] = triplet2;151
}152
if (!isValidRequest)153

{154
throw new HttpException(404, "This is an invalid webresource request.");155
}156
//if (!DebugMode)157
if (!HttpContext.Current.IsDebuggingEnabled)158

{159
HttpCachePolicy cache = context.Response.Cache;160
cache.SetCacheability(HttpCacheability.Public);161
cache.VaryByParams["d"] = true;162
//cache.SetOmitVaryStar(true);163
cache.SetExpires(DateTime.Now + TimeSpan.FromDays(365));164
cache.SetValidUntilExpires(true);165
}166
Stream manifestResourceStream = null;167
StreamReader reader = null;168
try169

{170
manifestResourceStream = assembly.GetManifestResourceStream(webResource);171
if (manifestResourceStream != null)172

{173
context.Response.ContentType = contentType;174
if (performSubstitution)175

{176
reader = new StreamReader(manifestResourceStream, true);177
string input = reader.ReadToEnd();178
MatchCollection matchs = webResourceRegex.Matches(input);179
int startIndex = 0;180
StringBuilder builder = new StringBuilder();181
foreach (Match match in matchs)182

{183
builder.Append(input.Substring(startIndex, match.Index - startIndex));184
Group group = match.Groups["resourceName"];185
if (group != null)186

{187
string a = group.ToString();188
if (a.Length > 0)189

{190
//if (string.Equals(a, webResource, StringComparison.Ordinal))191
if (string.Equals(a, webResource))192

{193
throw new HttpException(404, "The resource '" + webResource + "' cannot contain a reference to itself.");194
}195
builder.Append(GetWebResourceUrlInternal(assembly, a, false));196
}197
}198
startIndex = match.Index + match.Length;199
}200
builder.Append(input.Substring(startIndex, input.Length - startIndex));201
StreamWriter writer = new StreamWriter(context.Response.OutputStream, reader.CurrentEncoding);202
writer.Write(builder.ToString());203
writer.Flush();204
}205
else206

{207
byte[] buffer = new byte[1024];208
Stream outputStream = context.Response.OutputStream;209
int count = 1;210
while (count > 0)211

{212
count = manifestResourceStream.Read(buffer, 0, 1024);213
outputStream.Write(buffer, 0, count);214
}215
outputStream.Flush();216
}217
}218
}219
finally220

{221
if (reader != null)222

{223
reader.Close();224
}225
if (manifestResourceStream != null)226

{227
manifestResourceStream.Close();228
}229
}230
}231
//context.Response.IgnoreFurtherWrites();232
}233

234
internal static string GetWebResourceUrl(Type type, string resourceName)235

{236
return GetWebResourceUrl(type, resourceName, false);237
}238

239
internal static string GetWebResourceUrl(Type type, string resourceName, bool htmlEncoded)240

{241
Assembly assembly = (Assembly) _typeAssemblyCache[type];242
if (assembly == null)243

{244
assembly = type.Assembly;245
_typeAssemblyCache[type] = assembly;246
}247

248
//string url = UrlPath.Combine(HttpRuntime.AppDomainAppVirtualPathString, GetWebResourceUrlInternal(assembly, resourceName, htmlEncoded));249
string url = GetWebResourceUrlInternal(assembly, resourceName, htmlEncoded);250

251
return url;252
}253

254
private static string GetWebResourceUrlInternal(Assembly assembly, string resourceName, bool htmlEncoded)255

{256

/**//*257
EnsureHandlerExistenceChecked();258
if (!_handlerExists)259
{260
string HttpWebResourceHandler_HandlerNotRegistered = @"The WebResource.axd handler must be registered in the configuration to process this request.261

262
<!-- Web.Config Configuration File -->263

264
<configuration>265
<system.web>266
<httpHandlers>267
<add verb="GET" path="WebResource.axd" type="XCtrlLib.WebCtrl.HttpWebResourceHandler, XCtrlLib" />268
</httpHandlers>269
</system.web>270
</configuration>271
";272
throw new InvalidOperationException(HttpWebResourceHandler_HandlerNotRegistered);273
}274
*/275
Pair assemblyInfoWithAssert = (Pair) _assemblyInfoCache[assembly];276
if (assemblyInfoWithAssert == null)277

{278
assemblyInfoWithAssert = GetAssemblyInfoWithAssert(assembly);279
_assemblyInfoCache[assembly] = assemblyInfoWithAssert;280
}281
AssemblyName first = (AssemblyName) assemblyInfoWithAssert.First;282
long assemblyDate = (long) assemblyInfoWithAssert.Second;283
string text = first.Version.ToString();284
int num2 = CreateWebResourceUrlCacheKey(assembly, resourceName, htmlEncoded);285
string text2 = (string) _urlCache[num2];286
if (text2 == null)287

{288
string assemblyName;289
if (assembly.GlobalAssemblyCache)290

{291
if (assembly == typeof(HttpContext).Assembly)292

{293
assemblyName = "s";294
}295
else296

{297
StringBuilder builder = new StringBuilder();298
builder.Append('f');299
builder.Append(first.Name);300
builder.Append(',');301
builder.Append(text);302
builder.Append(',');303
if (first.CultureInfo != null)304

{305
builder.Append(first.CultureInfo.ToString());306
}307
builder.Append(',');308
byte[] publicKeyToken = first.GetPublicKeyToken();309
for (int i = 0; i < publicKeyToken.Length; i++)310

{311
builder.Append(publicKeyToken[i].ToString("x2", CultureInfo.InvariantCulture));312
}313
assemblyName = builder.ToString();314
}315
}316
else317

{318
assemblyName = "p" + first.Name;319
}320
text2 = FormatWebResourceUrl(assemblyName, resourceName, assemblyDate, htmlEncoded);321
_urlCache[num2] = text2;322
}323
return text2;324
}325

326
private static string FormatWebResourceUrl(string assemblyName, string resourceName, long assemblyDate, bool htmlEncoded)327

{328
//string resStringEncrypted = assemblyName + "|" + resourceName;329
//string resStringEncrypted = Page.EncryptString(assemblyName + "|" + resourceName);330
string resStringEncrypted = Utils.EncryptString(assemblyName + "|" + resourceName);331

332
resStringEncrypted = HttpContext.Current.Server.UrlEncode(resStringEncrypted);333
if (htmlEncoded)334

{335

return string.Format(CultureInfo.InvariantCulture, "WebResource.axd?d={0}&t={1}", new object[]
{ resStringEncrypted, assemblyDate });336
}337

return string.Format(CultureInfo.InvariantCulture, "WebResource.axd?d={0}&t={1}", new object[]
{ resStringEncrypted, assemblyDate });338
}339

340
[FileIOPermission(SecurityAction.Assert, Unrestricted=true), AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]341
private static Pair GetAssemblyInfoWithAssert(Assembly assembly)342

{343
AssemblyName x = assembly.GetName();344
return new Pair(x, File.GetLastWriteTime(new Uri(x.CodeBase).LocalPath).Ticks);345
}346

347
private static int CreateWebResourceUrlCacheKey(Assembly assembly, string resourceName, bool htmlEncoded)348

{349
return HashCodeCombiner.CombineHashCodes(HashCodeCombiner.CombineHashCodes(assembly.GetHashCode(), resourceName.GetHashCode()), htmlEncoded.GetHashCode());350
}351

352
}353
}354

1
using System;2
using System.Web;3

4
namespace XCtrlLib.WebCtrl5


{6

/**//// <summary>7
/// ExceptionUtil 的摘要说明。8
/// </summary>9
//public class ExceptionUtil10
internal class ExceptionUtil11

{12
// internal static ArgumentException ParameterInvalid(string parameter)13
// {14
// return new ArgumentException(System.Web.SR.GetString("Parameter_Invalid", new object[] { parameter }), parameter);15
// }16

17
internal static ArgumentException ParameterNullOrEmpty(string parameter)18

{19
//return new ArgumentException(System.Web.SR.GetString("Parameter_NullOrEmpty", new object[] { parameter }), parameter);20
return new ArgumentException("Parameter_NullOrEmpty", parameter);21
}22

23
// internal static ArgumentException PropertyInvalid(string property)24
// {25
// return new ArgumentException(System.Web.SR.GetString("Property_Invalid", new object[] { property }), property);26
// }27
//28
// internal static ArgumentException PropertyNullOrEmpty(string property)29
// {30
// return new ArgumentException(System.Web.SR.GetString("Property_NullOrEmpty", new object[] { property }), property);31
// }32
//33
// internal static InvalidOperationException UnexpectedError(string methodName)34
// {35
// return new InvalidOperationException(System.Web.SR.GetString("Unexpected_Error", new object[] { methodName }));36
// }37
}38
}39

1
using System;2
using System.Globalization;3
using System.IO;4
using System.Web;5
using System.Web.UI;6

7
namespace XCtrlLib.WebCtrl8


{9
internal class HashCodeCombiner10

{11
private long _combinedHash;12

13
internal HashCodeCombiner()14

{15
//this._combinedHash = 0x1505;16
this._combinedHash = 5381;17
}18

19
internal HashCodeCombiner(long initialCombinedHash)20

{21
this._combinedHash = initialCombinedHash;22
}23

24
internal void AddArray(string[] a)25

{26
if (a != null)27

{28
int length = a.Length;29
for (int i = 0; i < length; i++)30

{31
this.AddObject(a[i]);32
}33
}34
}35

36
internal void AddInt(int n)37

{38
this._combinedHash = ((this._combinedHash << 5) + this._combinedHash) ^ n;39
}40

41
internal void AddObject(bool b)42

{43
this.AddInt(b.GetHashCode());44
}45

46
internal void AddObject(byte b)47

{48
this.AddInt(b.GetHashCode());49
}50

51
internal void AddObject(int n)52

{53
this.AddInt(n);54
}55

56
internal void AddObject(long l)57

{58
this.AddInt(l.GetHashCode());59
}60

61
internal void AddObject(object o)62

{63
if (o != null)64

{65
this.AddInt(o.GetHashCode());66
}67
}68
//69
// internal void AddResourcesDirectory(string directoryName)70
// {71
// DirectoryInfo info = new DirectoryInfo(directoryName);72
// if (info.Exists)73
// {74
// this.AddObject(directoryName);75
// foreach (FileData data in FileEnumerator.Create(directoryName))76
// {77
// if (data.IsDirectory)78
// {79
// this.AddResourcesDirectory(data.FullName);80
// continue;81
// }82
// string virtualPath = data.FullName;83
// if (Util.GetCultureName(virtualPath) == null)84
// {85
// this.AddExistingFile(virtualPath);86
// }87
// }88
// this.AddDateTime(info.CreationTimeUtc);89
// }90
// }91

92
internal static int CombineHashCodes(int h1, int h2)93

{94
return (((h1 << 5) + h1) ^ h2);95
}96

97
internal static int CombineHashCodes(int h1, int h2, int h3)98

{99
return CombineHashCodes(CombineHashCodes(h1, h2), h3);100
}101

102
internal static int CombineHashCodes(int h1, int h2, int h3, int h4)103

{104
return CombineHashCodes(CombineHashCodes(h1, h2), CombineHashCodes(h3, h4));105
}106

107
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5)108

{109
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), h5);110
}111

112
// internal static string GetDirectoryHash(VirtualPath virtualDir)113
// {114
// HashCodeCombiner combiner = new HashCodeCombiner();115
// combiner.AddDirectory(virtualDir.MapPathInternal());116
// return combiner.CombinedHashString;117
// }118

119
internal long CombinedHash120

{121
get122

{123
return this._combinedHash;124
}125
}126

127
internal int CombinedHash32128

{129
get130

{131
return this._combinedHash.GetHashCode();132
}133
}134

135
internal string CombinedHashString136

{137
get138

{139
return this._combinedHash.ToString("x", CultureInfo.InvariantCulture);140
}141
}142
}143
}144

145

1
using System;2
using System.Security.Permissions;3
using System.Web;4

5
namespace XCtrlLib.WebCtrl6


{7
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]8
public interface IResourceUrlGenerator9

{10
string GetResourceUrl(Type type, string resourceName);11
}12
}13

1
using System;2

3
namespace XCtrlLib.WebCtrl4


{5

/**//// <summary>6
/// StringUtil 的摘要说明。7
/// </summary>8
public class StringUtil9

{10
public StringUtil()11

{12
}13

14
public static bool IsNullOrEmpty(string str)15

{16
if(str == null || str == string.Empty)17
return true;18
else19
return false;20
}21
}22
}23

1
using System;2
using System.Collections;3
using System.Collections.Specialized;4
using System.ComponentModel;5
using System.Security.Permissions;6
using System.Text;7
using System.Web;8
using System.Web.UI;9
using System.Web.Handlers;10
using System.Web.Util;11

12
using System.Reflection;13
using System.Globalization;14
using System.IO;15

16
namespace XCtrlLib.WebCtrl17


{18

/**//// <summary>19
/// ClientScriptManager 的摘要说明。20
/// </summary>21
public class ClientScriptManager22

{23
private Page _owner;24

25
public ClientScriptManager(Page owner)26

{27
this._owner = owner;28
}29

30
public void RegisterClientCssResource(Type type, string resourceName)31

{32
if (type == null)33

{34
throw new ArgumentNullException("type");35
}36

37
string url = this.GetWebResourceUrl(type, resourceName);38

39
if (StringUtil.IsNullOrEmpty(url))40

{41
throw ExceptionUtil.ParameterNullOrEmpty("url");42
}43

44
string strCss = "\r\n <link type=\"text/css\" href=\"" + HttpUtility.HtmlAttributeEncode(url) + "\" rel=\"stylesheet\">";45
//<link type="text/css" href="/Sol.WebUI/inc/style.css" rel="stylesheet">46

47
LiteralControl ctrlHeader = (LiteralControl)this._owner.Controls[0];48
string headerOri = ctrlHeader.Text;49
int posAdd = headerOri.ToLower().LastIndexOf("</title>") + 8;50
if(headerOri.IndexOf(strCss) == -1)51

{52
string headerText = headerOri.Insert(posAdd,strCss);53
ctrlHeader.Text = headerText;54
}55
}56

57
public void RegisterClientScriptResource(Type type, string resourceName)58

{59
if (type == null)60

{61
throw new ArgumentNullException("type");62
}63
string url = this.GetWebResourceUrl(type, resourceName);64
this.RegisterClientScriptInclude(type, resourceName, url);65
}66

67
public void RegisterClientScriptInclude(Type type, string key, string url)68

{69
if (type == null)70

{71
throw new ArgumentNullException("type");72
}73
if (StringUtil.IsNullOrEmpty(url))74

{75
throw ExceptionUtil.ParameterNullOrEmpty("url");76
}77
string script = "\r\n<script type=\"text/javascript\" src=\"" + HttpUtility.HtmlAttributeEncode(url) + "\"></script>";78
//this.RegisterScriptBlock(CreateScriptIncludeKey(type, key), script, ClientAPIRegisterType.ClientScriptBlocks);79
if(!this._owner.IsClientScriptBlockRegistered(key))80
this._owner.RegisterClientScriptBlock(key,script);81
}82

83
public string GetWebResourceUrl(Type type, string resourceName)84

{85
return GetWebResourceUrl(this._owner, type, resourceName, false);86
}87

88
internal static string GetWebResourceUrl(Page owner, Type type, string resourceName, bool htmlEncoded)89

{90
if (type == null)91

{92
throw new ArgumentNullException("type");93
}94
if (StringUtil.IsNullOrEmpty(resourceName))95

{96
throw new ArgumentNullException("resourceName");97
}98
// //if ((owner == null) || !owner.DesignMode)99
// if ((owner == null) || !owner.Site.DesignMode)100
// {101
// return HttpWebResourceHandler.GetWebResourceUrl(type, resourceName, htmlEncoded);102
// }103

104
if (owner == null)105

{106
return HttpWebResourceHandler.GetWebResourceUrl(type, resourceName, htmlEncoded);107
}108
if (owner.Site == null)109

{110
return HttpWebResourceHandler.GetWebResourceUrl(type, resourceName, htmlEncoded);111
}112
else if(!owner.Site.DesignMode)113

{114
return HttpWebResourceHandler.GetWebResourceUrl(type, resourceName, htmlEncoded);115
}116

117
ISite site = owner.Site;118
if (site != null)119

{120
IResourceUrlGenerator generator = site.GetService(typeof(IResourceUrlGenerator)) as IResourceUrlGenerator;121
if (generator != null)122

{123
return generator.GetResourceUrl(type, resourceName);124
}125
}126
return resourceName;127
}128

129
}130
}131

1
using System;2
using System.IO;3
using System.Text;4
using System.Web;5
using System.Security.Cryptography;6

7
namespace XCtrlLib.WebCtrl8


{9
internal class Utils10

{11

Constructors#region Constructors12

13
public Utils()14

{15
}16

17
#endregion18

19

private static byte[] DESKey = new byte[]
{11,23,93,102,72,41,18,12};20

private static byte[] DESIV = new byte[]
{75,158,46,97,78,57,17,36};21

22

/**//// <summary>23
/// 加密方法24
/// </summary>25
/// <param name="strSource">待加密的串</param>26
/// <returns>经过加密的串</returns>27
public static string EncryptString(string strSource)28

{29
MemoryStream ms = new MemoryStream();30
DESCryptoServiceProvider provider = new DESCryptoServiceProvider();31
ICryptoTransform cryptoTransform = provider.CreateEncryptor(DESKey, DESIV);32
CryptoStream cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write);33
StreamWriter sw = new StreamWriter(cs);34
sw.Write(strSource);35
sw.Flush();36
cs.FlushFinalBlock();37
ms.Flush();38
string strResult = Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);39

40
return strResult;41
}42

43

/**//// <summary>44
/// 解密方法45
/// </summary>46
/// <param name="strSource">待解密的串</param>47
/// <returns>经过解密的串</returns>48
public static string DecryptString(string strSource)49

{50
byte[] input = Convert.FromBase64String(strSource);51
MemoryStream ms = new MemoryStream(input);52
DESCryptoServiceProvider provider = new DESCryptoServiceProvider();53
ICryptoTransform cryptoTransform = provider.CreateDecryptor(DESKey, DESIV);54
CryptoStream cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Read);55
StreamReader sr = new StreamReader(cs);56
string strResult = sr.ReadToEnd();57

58
return strResult;59
}60
}61
}
应用时,在Web.config文件中作以下设置:
<httpHandlers>
<add verb="*" path="progress.ashx" type="XCtrlLib.WebCtrl.HttpUploadHandler, XCtrlLib"/>
<add verb="GET" path="WebResource.axd" type="XCtrlLib.WebCtrl.HttpWebResourceHandler, XCtrlLib" />
</httpHandlers>
即可象.NET 2.0中一样向客户端发送资源。
客户端调用:
ClientScriptManager mgr = new ClientScriptManager(this.Page);
string leftUrl = mgr.GetWebResourceUrl(typeof(XCtrlLib.WebCtrl.ResBag),"XCtrlLib.WebCtrl.Res.images.prev.gif");
this.Image1.ImageUrl = leftUrl;