Äú¿ÉÒÔ¾èÖú£¬Ö§³ÖÎÒÃǵĹ«ÒæÊÂÒµ¡£

1Ôª 10Ôª 50Ôª





ÈÏÖ¤Â룺  ÑéÖ¤Âë,¿´²»Çå³þ?Çëµã»÷Ë¢ÐÂÑéÖ¤Âë ±ØÌî



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓÆµ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Modeler   Code  
»áÔ±   
 
   
 
 
     
   
 ¶©ÔÄ
  ¾èÖú
WCF4.0 ¨C- RESTful WCF Services£¨¶þ£©
 
×÷Õߣº»úÆ÷ÈË À´Ô´£ºCSDN ·¢²¼ÓÚ 2015-7-13
  3503  次浏览      28
 

WCF4.0 ¨C- RESTful WCF Services (4) (Basic Security)

ÔÚREST¼Ü¹¹µÄWCF·þÎñÖУ¬Ëü²»ÏñÒ»°ãµÄWCF·þÎñ°ó¶¨£¬ÓÐÅäÌ׵ݲȫģʽ£¬ÊµÏÖÆðÀ´ÄÇô¼òµ¥¡£REST WCF·þÎñÖ»ÄÜÔÚ´«Êä²ã¼ÓÃÜ£¬¶øÒ»°ãµÄWCF ·þÎñ¿ÉÒÔÔÚÏûÏ¢²ã¼ÓÃÜ¡£Òò´Ë REST WCF·þÎñÆôÓÃASP.NET¼æÈÝģʽºó£¬ËüµÄ°²È«ÊÇÓÉASP.NETÀ´±£Ö¤µÄ¡£±¾ÆªÎÄÕÂÖ÷Òª½éÉÜÔÚ REST WCF ÖÐÈçºÎʵÏÖ×î¼òµ¥µÄ Username ÑéÖ¤¡£

ÔÚSOAPЭÒéµÄWCFÖУ¬¿ÉÒÔͨ¹ýSOAPHeader£¨MessageHeader)À´ÊµÏÖÓû§ÃûÃÜÂëµÄ´«Ê䣬ÔçÔÚWebServiceʱ´úÎÒÃǾÍÕâôÓùýÁË¡£ÔÚREST WCFÖУ¬ÎÒÃÇ¿ÉÒÔÀûÓà HttpHeader À´Íê³ÉÕâһĿ±ê¡£ £¨Äã¿É²»»áÏëÔÚÿ¸ö·þÎñÆõÔ¼Àï¼ÓÉÏÓû§ºÍÃÜÂëµÄ²ÎÊý°É...)

Ê×ÏÈÔÚ·þÎñÖмÓÈëÈçÏ·½·¨ÓÃÓÚУÑ飬HeaderµÄÐÅÏ¢£ºÈç¹û Header ÖÐ Authorization µÄ×Ö·û´®²»ÊÇ"fangxing/123" ÄÇô¾Í½«·µ»Ø 405 MethodNotAllowed µÄ´íÎó¡£Õâ¸ö×Ö·û´®µÄÄÚÈÝ¿ÉÒÔ×Ô¶¨Ò壬·´Õý·þÎñ¶Ë¸ù¾ÝijÖÖ¹æÔò¼ì²éÕâ¸ö×Ö·û´®¡£

private bool CheckAuthorization()  
{
var ctx = WebOperationContext.Current;
var auth = ctx.IncomingRequest.Headers[HttpRequestHeader.Authorization];
if (string.IsNullOrEmpty(auth) || auth != "fangxing/123")
{
ctx.OutgoingResponse.StatusCode = HttpStatusCode.MethodNotAllowed;
return false;
}
return true;
}

È»ºóÔÚÿһ¸ö·þÎñÆõÔ¼µÄʵÏÖÖУ¬¶¼È¥µ÷ÓÃËü¡£

[WebGet(UriTemplate = "All")]
public List<Task> GetTask()
{
if (!CheckAuthorization())
return null;
return GetData();
}
[WebGet(UriTemplate = "{taskId}")]
public Task GetTaskById(string taskId)
{
if (!CheckAuthorization())
return null;
return GetData().FirstOrDefault(t => t.Id==taskId);
}

ÏÖÔڵķþÎñ£¬Èç¹ûÖ±½Óͨ¹ýä¯ÀÀÆ÷·ÃÎÊ£¬½«µÃµ½ 405 MethodNotAllowed µÄ´íÎó£º

¿Í»§¶ËÖ»ÒªÏàÓ¦µÄÑéÖ¤Ðżӵ½ RequestHeader ÖÐÈ¥£¬¾Í¿ÉÒÔ·ÃÎÊÁË¡£¿Í»§¶Ë¿ÉÒÔʹÓõ¥ÀýģʽÉè¼Æ Client ¶ÔÏó¡£
ÕâÑù¾Í²»ÓÃÿ´Îµ÷Óö¼È¥¼ÓÑéÖ¤ÐÅÏ¢ÁË¡£

var url = "http://localhost:3433/TaskService/All";  
var client = new HttpClient();
client.DefaultHeaders.Add("Authorization", "fangxing/123");
var resp = client.Get(url);

ÕâÀïʹÓõÄÊÇ Microsoft.Http.HttpClient (WCF REST Starter Kit) ¶ø·Ç System.Net.WebClient

»ØÍ·¿´·þÎñ¶Ë´úÂ룬ÿ¸ö·þÎñʵÏÖÖж¼ÐèÒª¼ÓÉÏ CheckAuthorization() ÊDz»ÊǺܷ³£¿

OK£¬ÎÒÃÇÖªµÀÕâ¸ö REST WCF·þÎñÊdzÐÔØÔÚÒ»¸öWeb ApplicationÉϵģ¬ ͨ¹ýÍù RouteTable ÖÐ×¢²á WebServiceHostFactory À´¼¤»î·þÎñ¶ÔÏóµÄ¡£ ÄÇôֻҪ¶ÔÕâ¸ö WebServiceHostFactory ×öЩ¡°Êֽ𱣬¾Í¿ÉÒÔʵÏÖ·þÎñ¶ËÑéÖ¤µÄͳһÀ¹½Ø£¬´úÂëÈçÏ¡£(Ò»°ãµÄ WCF Ò²¿ÉÒÔÀûÓô˷½·¨¶Ô MessageHeader ½øÐÐÀ¹½ØÐ£Ñ飩

public class SecureWebServiceHostFactory : WebServiceHostFactory  
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var host = base.CreateServiceHost(serviceType, baseAddresses);
host.Authorization.ServiceAuthorizationManager = new MyServiceAuthorizationManager();
return host;
}

public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
var host = base.CreateServiceHost(constructorString, baseAddresses);
host.Authorization.ServiceAuthorizationManager = new MyServiceAuthorizationManager();
return host;
}
}

public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
protected override bool CheckAccessCore(OperationContext operationContext)
{
var ctx = WebOperationContext.Current;
var auth = ctx.IncomingRequest.Headers[HttpRequestHeader.Authorization];
if (string.IsNullOrEmpty(auth) || auth != "fangxing/123")
{
ctx.OutgoingResponse.StatusCode = HttpStatusCode.MethodNotAllowed;
return false;
}
return true;
}
}

RegisterRoutes ÀïµÄ¹¤³§ÀàÒ²ÐèÒªÏàÓ¦µÄÐÞ¸ÄÏ£º

var securewebServiceHostFactory = new SecureWebServiceHostFactory();  
RouteTable.Routes.Add(new ServiceRoute("TaskService",
securewebServiceHostFactory, typeof(TaskService)));

ÕâÑù·þÎñ¶Ë´úÂë¾Í¿ÉÒÔÈ¥µô CheckAuthorization() ¶ø°ÑÑéÖ¤¹¤×÷¶¼½»¸ø SecureWebServiceHostFactory ÁË¡£

ÕâÖÖÑéÖ¤·½Ê½£¬ÆäʵҲÊÇÏÖÔÚ Windows Auzer Access Control µÄÔ­ÐÍ¡£ Ö»²»¹ýÕâ¸ö Authoriztion µÄ·þÎñÊÇרÃŵÄServices°ÕÁË¡£

1. ¿Í»§¶ËÏÈ´Ó·¢²¼ÁîÅÆµÄ·þÎñ»ñÈ¡ÁîÅÆ£»

2. ¿Í»§¶ËÄÃ×ÅÁîÅÆÌá½»µ½ÏÖÔڵķþÎñ£»

3.·þÎñ¶Ë½«¿Í»§¶ËÁîÅÆÄõ½·¢²¼ÁîÅÆµÄ·þÎñÉÏУÑé¡£

WCF4.0 ¨C- RESTful WCF Services (ʵÀý) (²¢·¢Í¬²½·þÎñ SyncService)

×î½üд×Ô¶¯»¯²âÊÔʱÓöµ½Ò»¸öÎÊÌ⣺ ÎÒÃÇÔÚ½øÐÐÒ»¸ö²¢·¢²âÊԵĹý³ÌÖУ¬ÐèÒªËùÓпͻ§¶Ë²âÊÔ´úÂ룬ÔÚij¸öʱ»úͬ²½¡£»ØÏëËùѧµ½µÄ£¬Ïß³Ìͬ²½ÊֶκܶàÁË£¬Í¬Ò»Ì¨PCÉϵĽø³Ì¼äͬ²½Ò²¿ÉÒÔͨ¹ýMetuxʵÏÖ£¬¶àPCµÄʱºòÔõô°ì¡£ÒòΪ×î½üÔÚѧϰREST WCF£¬×ÔÈ»Ïëµ½Ëü£¬ÓÃËüÀ´×ö¸öͬ²½·þÎñ£¬¼´¿ÉÒÔ½â¾ö¶àỊ̈߳¬¶à½ø³Ì£¬¶àPCͬ²½£¬»¹¿ÉÒÔÖ§³Ö¿çÓïÑÔ£¬ÕæÊÇÒ»¾Ù¶àµÃ¡£(ÀàËÆµÄ½â¾ö·½°¸»¹ÓÐPNUNIT£¬ËüÊÇͨ¹ý.Net RemotingʵÏֵģ¬ÒòΪËü»¹ÒªÐ´ÅäÖ㬻¹ÒªÆðLancher/Agent£¬Óе㷳)¡£

1. SyncService µÄÖ÷Òª¹¦ÄÜ¡ª¡ªBarrier(À¸Õ¤)£º

½èÓÃPNUNITµÄ¸ÅÄîBarrier£¬Ò²¾ÍÊÇÒì²½¹ý³ÌÖеÄͬ²½µã£¬½øµ½BarrierÀïµÄËùÓжÔÏó¶¼ÒªµÈ´ýÆäËû¶ÔÏó½øÈë¡£ÕâЩ¶ÔÏó¿ÉÒÔÊDz»Í¬µÄỊ̈߳¬½ø³Ì(²»Í¬PC£¬²»Í¬ÓïÑÔʵÏֵĿͻ§¶Ë)£¬¹ý³ÌÈçÏÂͼ£º3¸ö¿Í»§¶ËÆô¶¯Ö®ºó£¬ÓпìÓÐÂý£¬µ«ÊÇÔÚBarrier´¦½øÐÐÒ»´Îͬ²½£¬Ïȵ½µÄµÈ´ýºóµ½µÄ¡£

¾Ù¸öʵ¼ÊÀý×Ó£º ¼ÙÈçÎÒÃÇҪʵÏÖÁ½¸ö¿Í»§¶ËͨÐŵŦÄܵIJâÊÔ£¬±ØÐëÊÇÁ½¸ö¿Í»§¶ËͬʱÉÏÏß¡£ÄÇôÎÒÃÇ¿ÉÒÔÔÚ´úÂëÖÐÉè¼ÆÒ»¸öbarrier£¬ÈÃË«·½¶¼È·ÈÏÉÏÏßÖ®ºó£¬ÔÙ½øÐÐͨÐŲâÊÔ¡£

(1) ×¼±¸Barrier

ÕâÀïÓеãÒªÌØ±ð˵Ã÷µÄµØ·½var init = SyncService.Init("Barrier_Logon", "Client1", "Client2");  
// Æô¶¯Client1
Process.Start("Client1.exe");
// Æô¶¯Client2
Process.Start("Client2.exe");

(2) Client1

// client1怬  
var client1 = Login("Client1");
// ͬ²½£¬µÈ´ýClient2µÇ¼
var enter = SyncService.Enter("Barrier_Logon", "Client1");
// client1 ºÍ client2 Ï໥ͨÐÅ ...

(3) Client2 ºÍ Client1 ÀàËÆ

// client2怬  
var client2 = Login("Client2");
// ͬ²½£¬µÈ´ýClient1µÇ¼
var enter = SyncService.Enter("Barrier_Logon", "Client2");
// client1 ºÍ client2 Ï໥ͨÐÅ ...

2. SyncService µÄÏûÏ¢½»»»¹¦ÄÜ¡ª¡ªSetMessage/GetMessage£º

ÎÒÃÇ»¹¿ÉÒÔͨ¹ýSyncServiceÖеÄÏûÏ¢ÈÝÆ÷½øÐÐÏûÏ¢´«µÝ¡£ÈçÏÂͼ£º

ÔÚÒì²½µÄÁ½¶Î´úÂëÖУ¬ÉèÖÃͬ²½µã£¬±£Ö¤ GetMessage ÊÇÔÚ SetMessage Ö®ºó·¢Éú¡£ÕâÒ»µãÊDz¢ÐвâÊÔÖÐÊǺܳ£¼ûµÄ´¦Àí¡£

Client1µÄ´úÂ룺

// ÉèÖÃÏûÏ¢¸øclient2  
var set = SyncService.SetMessage("Barrier", "key", "hello client2");
// ½øÈëBarrier, µÈ´ýclient2
var enter = SyncService.Enter("Barrier", "Client1");

Client2µÄ´úÂ룺

// ½øÈëBarrier,µÈ´ýclient1  
var enter = SyncService.Enter("Barrier", "Client2");
// È¡µÃÏûÏ¢
var get = SyncService.GetMessage("Barrier", "key");
// È·ÈÏ»ñµÃÏûÏ¢£¬ÊÇ"hello client2"
Assert.AreEqual(get, "hello client2");

3. SyncServiceµÄʵÏÖ

Èç¹ûÉÏÃæµÄ²¢Ðд¦Àí´úÂëÀí½âÁ˵ϰ£¬SyncServiceµÄʵÏ־ͺܺÃÍÆ¶Ï³öÀ´ÁË¡£·þÎñ¶Ëά»¤Ò»¸öDictionary<string, SyncGroup>µÄÈÝÆ÷£¬Ã¿¸ö¿Í»§¶ËEnterʱ£¬µ÷ÓöÔÓ¦µÄManualResetEvent.Set()½âËø¡£È»ºóWaitAllÆäËûµÄManualResetEvent£¬´Ó¶øÊµÏÖͬ²½¡£

using System;  
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;
using System.Threading;
using System.Runtime.Serialization;

namespace SyncService
{
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class SyncService
{
private static Dictionary<string, SyncGroup> _syncPool = new Dictionary<string, SyncGroup>();

[WebGet(UriTemplate="Init/{barrier}/{targetnames}")]
public string Init(string barrier, string targetnames)
{
var ctx = WebOperationContext.Current;
try
{
lock (_syncPool)
{
_syncPool[barrier] = new SyncGroup();
var syncGroup = _syncPool[barrier];
var targets = targetnames.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
Array.ForEach(targets, t => syncGroup.ResetEventDict.Add(t, new ManualResetEvent(false)));
}
return "ok";
}
catch (Exception ex)
{
return ex.Message;
}
}

[WebGet(UriTemplate = "Enter/{barrier}/{targetname}/{timeout=60000}")]
public string Enter(string barrier, string targetname, string timeout)
{
var ctx = WebOperationContext.Current;
try
{
var syncObj = _syncPool[barrier];
var target = syncObj.ResetEventDict[targetname];
target.Set();
var intTimeout = int.Parse(timeout);
var success = WaitHandle.WaitAll(syncObj.ResetEventDict.Values.ToArray(), intTimeout);
if (success)
return "ok";
else
return "timeout";
}
catch (Exception ex)
{
return ex.Message;
}
}

[WebGet(UriTemplate = "SetMessage/{barrier}/{key}/{message=null}")]
public string SetMessage(string barrier, string key, string message)
{
var ctx = WebOperationContext.Current;
try
{
var syncObj = _syncPool[barrier];
lock (syncObj)
{
var query = syncObj.Messages.FirstOrDefault(m => m.Key == key);
syncObj.Messages.Remove(query);
var messageInfo = new MessageInfo
{
BarrierName = barrier,
Key = key,
Message = message,
UpdateDateTime = DateTime.Now
};
syncObj.Messages.Add(messageInfo);
}
return "ok";
}
catch (Exception ex)
{
return ex.Message;
}
}

[WebGet(UriTemplate = "GetMessage/{barrier}/{key}")]
public string GetMessage(string barrier, string key)
{
var ctx = WebOperationContext.Current;
try
{
var syncObj = _syncPool[barrier];
var query = syncObj.Messages.FirstOrDefault(m => m.Key == key);
return query.Message;
}
catch (Exception ex)
{
return ex.Message;
}
}

[WebGet(UriTemplate = "ListMessages/{barrier=all}", ResponseFormat=WebMessageFormat.Xml)]
public List<MessageInfo> ListMessages(string barrier)
{
var ctx = WebOperationContext.Current;
try
{
var messages = new List<MessageInfo>();
if (barrier == "all")
_syncPool.Values.ToList().ForEach(t => messages.AddRange(t.Messages));
else
messages = _syncPool[barrier].Messages;
return messages;
}
catch
{
return null;
}
}

[WebGet(UriTemplate="Check", ResponseFormat=WebMessageFormat.Xml)]
public string Check()
{
return "Welcome to the SyncService! " +
DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString();
}

}

[DataContract]
[KnownType(typeof(MessageInfo))]
public class SyncGroup
{
internal Dictionary<string, ManualResetEvent> ResetEventDict { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public List<MessageInfo> Messages { get; set; }
[DataMember]
public Dictionary<string, string> States { get; set; }

public SyncGroup()
{
Messages = new List<MessageInfo>();
ResetEventDict = new Dictionary<string, ManualResetEvent>();
}
}

[DataContract]
public class MessageInfo
{
[DataMember]
public string BarrierName { get; set; }
[DataMember]
public string Key { get; set; }
[DataMember]
public string Message { get; set; }
[DataMember]
public string Identity { get; set; }
[DataMember]
public DateTime UpdateDateTime { get; set; }
}
}

ĬÈÏʹÓÃJSON¸ñʽ£¬ÁíÍâΪÁ˲鿴µ±Ç°µÄͬ²½µÄ×´¿öºÍÏûÏ¢£¬¿ÉÒÔͨ¹ý ListStates/ListMessages ²é¿´¡£

(1) ³õʼ»¯BarrierÔò·¢ËÍ£º http://server/SyncService/Init/MyBarrier/Client1,Client2

(2) ¿Í»§¶Ë½øÈëBarrierÔò·¢ËÍ: http://server/SyncService/Enter/MyBarrier/Client1/10000 (×îºóÊÇtimeoutÉ趨)

(3) ÉèÖÃÏûÏ¢Ôò·¢ËÍ: http://server/SyncService/SetMessage/MyBarrier/Key/MessageContent

(4) È¡µÃÏûÏ¢Ôò·¢ËÍ: http://server/SyncService/GetMessage/MyBarrier/Key

(5) ²é¿´ËùÓеġ°Ëø¡±Ôò·¢ËÍ£ºhttp://server/SyncService/ListStates (»òÕßÖ¸¶¨Ä³¸öBarrier: /MyBarrier)

(6) ²é¿´ËùÓеÄÏûÏ¢Ôò·¢ËÍ£ºhttp://server/SyncService/ListMessages(»òÕßÖ¸¶¨Ä³¸öBarrier: /MyBarrier)

(7) Çå¿ÕËùÓÐSyncGroupÔò·¢ËÍ£ºhttp://server/SyncService/Restart

Êǵģ¬È«²¿µÄ²Ù×÷È«²¿ÊÇ HttpRequest µÄ"GET", Òò´Ë¸÷ÖÖ¿Í»§¶Ë¶¼¿ÉÒÔÇáËɵ÷Ó㬺ܷ½±ã¡£ (ÓÃWCF´´½¨ÕâÑùÒ»¸ö·þÎñÒ²·Ç³£¼òµ¥È«²¿´úÂëÒ»°Ù¶àÐУ¬ÕýËùνÌìÏÂÎ书ÎÞ¿ì²»ÆÆ:)

ÉÏÆª:WCF4.0 ¨C- RESTful WCF Services£¨Ò»£©

   
3503 ´Îä¯ÀÀ       28
 
Ïà¹ØÎÄÕÂ

Éî¶È½âÎö£ºÇåÀíÀôúÂë
ÈçºÎ±àд³öÓµ±§±ä»¯µÄ´úÂë
ÖØ¹¹-ʹ´úÂë¸ü¼ò½àÓÅÃÀ
ÍŶÓÏîÄ¿¿ª·¢"±àÂë¹æ·¶"ϵÁÐÎÄÕÂ
 
Ïà¹ØÎĵµ

ÖØ¹¹-¸ÄÉÆ¼ÈÓдúÂëµÄÉè¼Æ
Èí¼þÖØ¹¹v2
´úÂëÕû½àÖ®µÀ
¸ßÖÊÁ¿±à³Ì¹æ·¶
 
Ïà¹Ø¿Î³Ì

»ùÓÚHTML5¿Í»§¶Ë¡¢Web¶ËµÄÓ¦Óÿª·¢
HTML 5+CSS ¿ª·¢
ǶÈëʽC¸ßÖÊÁ¿±à³Ì
C++¸ß¼¶±à³Ì
×îл¼Æ»®
DeepSeekÔÚÈí¼þ²âÊÔÓ¦ÓÃʵ¼ù 4-12[ÔÚÏß]
DeepSeek´óÄ£ÐÍÓ¦Óÿª·¢Êµ¼ù 4-19[ÔÚÏß]
UAF¼Ü¹¹ÌåϵÓëʵ¼ù 4-11[±±¾©]
AIÖÇÄÜ»¯Èí¼þ²âÊÔ·½·¨Óëʵ¼ù 5-23[ÉϺ£]
»ùÓÚ UML ºÍEA½øÐзÖÎöÉè¼Æ 4-26[±±¾©]
ÒµÎñ¼Ü¹¹Éè¼ÆÓ뽨ģ 4-18[±±¾©]

ʹÓÃdecj¼ò»¯Webǰ¶Ë¿ª·¢
Web¿ª·¢¿ò¼ÜÐγÉÖ®ÂÃ
¸üÓÐЧÂʵÄʹÓÃVisual Studio
MVP+WCF+Èý²ã½á¹¹´î½¨¿ò¼Ü
ASP.NETÔËÐлúÖÆÇ³Îö¡¾Í¼½â¡¿
±àд¸üºÃµÄC#´úÂë
10¸öVisual Studio¿ª·¢µ÷ÊÔ¼¼ÇÉ

.NET¿ò¼ÜÓë·Ö²¼Ê½Ó¦Óüܹ¹Éè¼Æ
.NET & WPF & WCFÓ¦Óÿª·¢
UML&.Net¼Ü¹¹Éè¼Æ
COM×é¼þ¿ª·¢
.NetÓ¦Óÿª·¢
InstallShield

ÈÕÕÕ¸Û .NET Framework & WCFÓ¦Óÿª·¢
Éñ»ªÐÅÏ¢ .NETµ¥Ôª²âÊÔ
±±¾© .NetÓ¦ÓÃÈí¼þϵͳ¼Ü¹¹
̨´ïµç×Ó .NET³ÌÐòÉè¼ÆÓ뿪·¢
ÈüÃÅÌú¿Ë C#Óë.NET¼Ü¹¹Éè¼Æ
¹ã¶«ºËµç .NetÓ¦ÓÃϵͳ¼Ü¹¹