วิธีการเพิ่มส่วนหัว HTTP ที่กำหนดเองให้กับทุกการโทร WCF?


162

ฉันมีบริการ WCF ที่โฮสต์ในบริการ Windows ลูกค้าที่ใช้บริการนี้จะต้องผ่านตัวระบุทุกครั้งที่พวกเขาเรียกวิธีการบริการ (เพราะตัวระบุนั้นมีความสำคัญต่อสิ่งที่เรียกว่าวิธีการที่ควรทำ) ฉันคิดว่าเป็นความคิดที่ดีที่จะนำตัวระบุนี้ไปใช้กับข้อมูลส่วนหัวของ WCF

หากเป็นความคิดที่ดีฉันจะเพิ่มตัวระบุลงในข้อมูลส่วนหัวโดยอัตโนมัติได้อย่างไร กล่าวอีกนัยหนึ่งเมื่อใดก็ตามที่ผู้ใช้เรียกใช้เมธอด WCF จะต้องเพิ่มตัวระบุลงในส่วนหัวโดยอัตโนมัติ

UPDATE: ลูกค้าที่ใช้บริการ WCF เป็นทั้งแอพพลิเคชั่น Windows และแอพพลิเคชั่น Windows Mobile (โดยใช้ Compact Framework)


1
คุณสามารถแก้ปัญหาของคุณได้หรือไม่?
ทำเครื่องหมายที่ดี

คุณได้รับสิ่งนี้เพื่อทำงานใน Compact Framework หรือไม่
Vaccano

คำตอบ:


185

ข้อดีของมันคือมันถูกใช้กับทุกการโทร

สร้างคลาสที่ดำเนินIClientMessageInspector ในการ BeforeSendRequest วิธีการเพิ่มหัวข้อที่กำหนดเองของคุณไปยังข้อความขาออก อาจมีลักษณะเช่นนี้:

    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request,  System.ServiceModel.IClientChannel channel)
{
    HttpRequestMessageProperty httpRequestMessage;
    object httpRequestMessageObject;
    if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
    {
        httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
        if (string.IsNullOrEmpty(httpRequestMessage.Headers[USER_AGENT_HTTP_HEADER]))
        {
            httpRequestMessage.Headers[USER_AGENT_HTTP_HEADER] = this.m_userAgent;
        }
    }
    else
    {
        httpRequestMessage = new HttpRequestMessageProperty();
        httpRequestMessage.Headers.Add(USER_AGENT_HTTP_HEADER, this.m_userAgent);
        request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
    }
    return null;
}

จากนั้นสร้างลักษณะการทำงานของจุดปลายที่ใช้ตัวตรวจสอบข้อความกับไคลเอนต์รันไทม์ คุณสามารถใช้ลักษณะการทำงานผ่านแอตทริบิวต์หรือผ่านการกำหนดค่าโดยใช้องค์ประกอบส่วนขยายพฤติกรรม

นี่เป็นตัวอย่างที่ดีของวิธีเพิ่มส่วนหัวผู้ใช้ - เอเจนต์ HTTP ให้กับข้อความคำขอทั้งหมด ฉันกำลังใช้สิ่งนี้ในลูกค้าของฉันไม่กี่คน นอกจากนี้คุณยังสามารถทำเช่นเดียวกันในด้านการให้บริการโดยการใช้IDispatchMessageInspector

นี่คือสิ่งที่คุณมีในใจ?

อัปเดต: ฉันพบรายการฟีเจอร์ของ WCF ที่ได้รับการสนับสนุนโดยเฟรมเวิร์กขนาดกะทัดรัด ฉันเชื่อว่าผู้ตรวจสอบข้อความจัดเป็น 'Channel Extensibility' ซึ่งตามโพสต์นี้ได้รับการสนับสนุนโดยกรอบงานขนาดกะทัดรัด


2
@ Mark, นี่คือคำตอบที่ยอดเยี่ยมจริงๆ ขอบคุณ ฉันลองทำสิ่งนี้ผ่าน net.tcp แต่ฉันใช้คอลเล็กชันส่วนหัวโดยตรง (ส่วนหัว Http ไม่ทำงาน) ฉันได้รับส่วนหัวด้วยโทเค็นของฉัน (ชื่อ) ในเหตุการณ์ ServiceHost AfterReceiveRequest แต่ไม่ใช่ค่า (ดูเหมือนจะไม่เป็นคุณสมบัติสำหรับค่าใช่หรือไม่) มีบางอย่างที่ฉันขาดหายไปหรือไม่? ฉันคาดว่าจะมีคู่ชื่อ / ค่าเป็นเมื่อฉันสร้างส่วนหัวมันถามฉันสำหรับ: request.Headers.Add (MessageHeader.CreateHeader (ชื่อ, ns, ค่า));
Program.X

13
+1 OutgoingMessagePropertiesคือสิ่งที่คุณต้องการในการเข้าถึง HTTP Headers - ไม่ใช่OutgoingMessageHeadersSOAP header
SliverNinja - MSFT

1
เพียงแค่รหัสที่ยอดเยี่ยม! :)
abhilashca

3
สิ่งนี้อนุญาตเฉพาะเอเจนต์ผู้ใช้ hardcoded ซึ่ง - ตามตัวอย่างที่ระบุ - ถูก hardcoded ใน web.config!
KristianB

1
นี่คือคำตอบที่ยอดเยี่ยม นอกจากนี้ยังจัดการกรณีและปัญหาเมื่อ HttpRequestMessageProperty.Name ยังไม่พร้อมใช้งานในคุณสมบัติข้อความ ด้วยเหตุผลบางอย่างการแก้จุดบกพร่องรหัสของฉันฉันรู้ว่าขึ้นอยู่กับเวลาปัญหาค่านี้ไม่ได้มี ขอบคุณมาร์ค!
carlos357

80

คุณเพิ่มลงในการโทรโดยใช้:

using (OperationContextScope scope = new OperationContextScope((IContextChannel)channel))
{
    MessageHeader<string> header = new MessageHeader<string>("secret message");
    var untyped = header.GetUntypedHeader("Identity", "http://www.my-website.com");
    OperationContext.Current.OutgoingMessageHeaders.Add(untyped);

    // now make the WCF call within this using block
}

จากนั้นฝั่งเซิร์ฟเวอร์ที่คุณใช้งาน:

MessageHeaders headers = OperationContext.Current.IncomingMessageHeaders;
string identity = headers.GetHeader<string>("Identity", "http://www.my-website.com");

5
ขอบคุณสำหรับโค้ดโค้ด แต่ด้วยสิ่งนี้ฉันต้องเพิ่มส่วนหัวทุกครั้งที่ฉันต้องการเรียกเมธอด ฉันต้องการทำให้กระบวนการนี้โปร่งใส ฉันหมายถึงการใช้งานครั้งเดียวทุกครั้งที่ผู้ใช้สร้างบริการลูกค้าและใช้วิธีการส่วนหัวของลูกค้าที่เพิ่มลงในข้อความโดยอัตโนมัติ
mrtaikandi

นี่คือลิงค์ MSDN ที่ดีพร้อมตัวอย่างเพื่อขยายตามคำแนะนำที่ให้ไว้ในคำตอบนี้: msdn.microsoft.com/en-us/library/…
atconway

1
ขอบคุณนี่เป็นโค้ดที่ยอดเยี่ยมหากคุณใช้ไลบรารีไคลเอนต์ที่กำหนดเอง วิธีนี้คุณไม่จำเป็นต้องใช้ messageinspector เพียงแค่สร้างวิธีการ wrapper ทั่วไปซึ่ง wraps การโทรของลูกค้าทุกคนใน
JustAMartin

3
โปรดทราบว่านี่เป็นปัญหาถ้าคุณทำสิ่งใด ๆ ของ async กับการโทรของคุณเพราะOperationContextScope(และOperationContext) คือThreadStatic- คำตอบของMark Goodจะทำงานโดยไม่ต้องพึ่งพาThreadStaticรายการ
zimdanen

2
นี่ไม่ได้เพิ่มส่วนหัว HTTP! มันเพิ่มส่วนหัวในซองจดหมาย SOAP
br3nt

32

หากคุณต้องการเพิ่มส่วนหัวเดียวกันในคำขอทั้งหมดไปยังบริการคุณสามารถทำได้โดยไม่ต้องมีการเข้ารหัสใด ๆ !
เพียงเพิ่มโหนดส่วนหัวที่มีส่วนหัวที่จำเป็นภายใต้โหนดปลายทางในไฟล์กำหนดค่าไคลเอนต์ของคุณ

<client>  
  <endpoint address="http://localhost/..." >  
    <headers>  
      <HeaderName>Value</HeaderName>  
    </headers>   
 </endpoint>  

18
นี่คือ SOAP Headers ( alaMessageHeader ) - ไม่ใช่ HTTP Headers
SliverNinja - MSFT

18

นี่คือโซลูชันที่มีประโยชน์อีกวิธีหนึ่งสำหรับการเพิ่มส่วนหัว HTTP ที่กำหนดเองลงในคำขอ WCF ของลูกค้าโดยใช้ChannelFactoryเป็นพร็อกซี สิ่งนี้จะต้องทำสำหรับแต่ละคำขอ แต่พอเพียงในการสาธิตอย่างง่ายถ้าคุณเพียงแค่ต้องทดสอบหน่วยพร็อกซี่ของคุณเพื่อเตรียมพร้อมสำหรับแพลตฟอร์มที่ไม่ใช่ NET

// create channel factory / proxy ...
using (OperationContextScope scope = new OperationContextScope(proxy))
{
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = new HttpRequestMessageProperty()
    {
        Headers = 
        { 
            { "MyCustomHeader", Environment.UserName },
            { HttpRequestHeader.UserAgent, "My Custom Agent"}
        }
    };    
    // perform proxy operations... 
}

1
ฉันลองคำแนะนำที่คล้ายกันอีก 4 ข้อและนี่เป็นข้อเสนอเดียวที่เหมาะกับฉัน
JohnOpincar

นี่เป็นการเพิ่มหัว HTTP จริง ๆ ขอบคุณ! :) แต่ jeez มันเป็นโค้ดที่ดูน่าเกลียด
br3nt

11

นี้คล้ายกับคำตอบ NimsDotNet แต่แสดงวิธีการเขียนโปรแกรม

เพียงเพิ่มส่วนหัวในการผูก

var cl = new MyServiceClient();

var eab = new EndpointAddressBuilder(cl.Endpoint.Address);

eab.Headers.Add( 
      AddressHeader.CreateAddressHeader("ClientIdentification",  // Header Name
                                         string.Empty,           // Namespace
                                         "JabberwockyClient"));  // Header Value

cl.Endpoint.Address = eab.ToEndpointAddress();

ฉันได้รับรหัสนี้ในการโทรปัจจุบันของฉัน (ฝั่งไคลเอ็นต์) .. ฉันจะรับค่า head นี้ได้อย่างไรใน System.ServiceModel.OperationContext? (ฝั่งเซิร์ฟเวอร์) (ฉันกำลังข้ามนิ้วของฉันว่าสิ่งนี้จะช่วยฉันได้)
granadaCoder

1
เข้าใจแล้ว! ส่วนหัว System.ServiceModel.Channels.MessageHeaders = operationContext.RequestContext.RequestMessage.Headers; int headerIndex = headers.FindHeader ("ClientIdentification", สตริง.Empty); var requestName = (headerIndex <0)? "UNKNOWN": ส่วนหัว GetHeader <string> (headerIndex);
granadaCoder

1
@granadaCoder ฉันรักไซต์นั้น! ;-)
ΩmegaMan

สิ่งนี้จะเพิ่มส่วนหัวในซองจดหมาย SOAP ไม่ใช่ส่วนหัว HTTP
br3nt

5
var endpoint = new EndpointAddress(new Uri(RemoteAddress),
               new[] { AddressHeader.CreateAddressHeader(
                       "APIKey", 
                       "",
                       "bda11d91-7ade-4da1-855d-24adfe39d174") 
                     });

12
นี่คือส่วนหัวของข้อความ SOAP ไม่ใช่ส่วนหัว HTTP
René

3

นี่คือสิ่งที่ใช้ได้ผลสำหรับฉันดัดแปลงจากการเพิ่มส่วนหัว HTTP ไปยัง WCF Calls

// Message inspector used to add the User-Agent HTTP Header to the WCF calls for Server
public class AddUserAgentClientMessageInspector : IClientMessageInspector
{
    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
    {
        HttpRequestMessageProperty property = new HttpRequestMessageProperty();

        var userAgent = "MyUserAgent/1.0.0.0";

        if (request.Properties.Count == 0 || request.Properties[HttpRequestMessageProperty.Name] == null)
        {
            var property = new HttpRequestMessageProperty();
            property.Headers["User-Agent"] = userAgent;
            request.Properties.Add(HttpRequestMessageProperty.Name, property);
        }
        else
        {
            ((HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]).Headers["User-Agent"] = userAgent;
        }
        return null;
    }

    public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {
    }
}

// Endpoint behavior used to add the User-Agent HTTP Header to WCF calls for Server
public class AddUserAgentEndpointBehavior : IEndpointBehavior
{
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(new AddUserAgentClientMessageInspector());
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }
}

หลังจากประกาศคลาสเหล่านี้คุณสามารถเพิ่มพฤติกรรมใหม่ให้กับลูกค้า WCF ของคุณดังนี้:

client.Endpoint.Behaviors.Add(new AddUserAgentEndpointBehavior());

สิ่งนี้จะไม่คอมไพล์: ข้อผิดพลาด CS0136 ไม่สามารถประกาศโลคัลหรือพารามิเตอร์ชื่อ 'คุณสมบัติ' ในขอบเขตนี้เนื่องจากชื่อนั้นจะใช้ในขอบเขตโลคัลที่ล้อมรอบเพื่อกำหนดโลคัลหรือพารามิเตอร์
Leszek P

เพียงลบอันที่ไม่ได้ใช้ออก
kosnkov

3

มันใช้งานได้สำหรับฉัน

TestService.ReconstitutionClient _serv = new TestService.TestClient();

using (OperationContextScope contextScope = new OperationContextScope(_serv.InnerChannel))
{
   HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();

   requestMessage.Headers["apiKey"] = ConfigurationManager.AppSettings["apikey"]; 
   OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = 
      requestMessage;
   _serv.Method(Testarg);
}

2

การเชื่อมโยงบริบทใน. NET 3.5 อาจเป็นสิ่งที่คุณกำลังมองหา มีสามกล่อง: BasicHttpContextBinding, NetTcpContextBinding และ WSHttpContextBinding โปรโตคอลบริบทโดยทั่วไปผ่านคู่คีย์ - ค่าในส่วนหัวของข้อความ ตรวจสอบการจัดการสถานะด้วยบทความบริการที่ทนทานในนิตยสาร MSDN


นอกจากนี้โปรดทราบว่าคุณตั้งค่าบริบทเพียงครั้งเดียวก่อนที่จะสร้างเซสชันกับเซิร์ฟเวอร์ จากนั้นบริบทจะอ่านได้อย่างเดียว หากคุณต้องการให้การตั้งค่าบริบทโปร่งใสในฝั่งไคลเอ็นต์คุณสามารถสืบทอดมาจากคลาสไคลเอ็นต์ proxt และในตัวสร้างคุณสามารถเพิ่มข้อมูลที่ประกอบขึ้นเป็นบริบทของคุณ จากนั้นทุกครั้งที่ไคลเอนต์สร้างอินสแตนซ์ของไคลเอนต์ proxt บริบทจะถูกสร้างและเพิ่มลงในอินสแตนซ์ของไคลเอ็นต์พร็อกซีโดยอัตโนมัติ
เมห์เม็ต Aras

2

ถ้าฉันเข้าใจความต้องการของคุณถูกต้องคำตอบง่ายๆก็คือ: คุณทำไม่ได้

นั่นเป็นเพราะลูกค้าของบริการ WCF อาจถูกสร้างขึ้นโดยบุคคลที่สามใด ๆ ที่ใช้บริการของคุณ

หากคุณมีการควบคุมลูกค้าในบริการของคุณคุณสามารถสร้างคลาสไคลเอนต์พื้นฐานที่เพิ่มส่วนหัวที่ต้องการและสืบทอดพฤติกรรมในชั้นเรียนของผู้ปฏิบัติงาน


1
ตกลงถ้าคุณกำลังสร้าง SOA อย่างแท้จริงคุณไม่สามารถสันนิษฐานได้ว่าลูกค้าทั้งหมดเป็นแบบ. NET รอจนกว่าธุรกิจของคุณจะได้รับ
SliverNinja - MSFT

2
นี่เป็นเรื่องจริงหรือ Java เว็บเซอร์วิสไคลเอ็นต์ไม่มีความสามารถในการเพิ่มชื่อ / ค่าให้กับส่วนหัว SOAP? ฉันพบว่ามันยากที่จะเชื่อ แน่นอนว่ามันจะเป็นการใช้งานที่แตกต่างกัน แต่นี่เป็นวิธีการแก้ปัญหาร่วมกัน
Adam

2

คุณสามารถระบุส่วนหัวที่กำหนดเองในMessageContract

คุณยังสามารถใช้ส่วนหัว <endpoint>ที่เก็บไว้ในไฟล์การกำหนดค่าและจะถูกคัดลอก allong ในส่วนหัวของข้อความทั้งหมดที่ส่งโดยลูกค้า / บริการ นี่คือประโยชน์ในการเพิ่มส่วนหัวคงที่บางอย่างง่ายดาย


3
นี่คือ SOAP Headers ( alaMessageHeader ) - ไม่ใช่ HTTP Headers
SliverNinja - MSFT

0

หากคุณต้องการเพิ่มส่วนหัว HTTP ที่กำหนดเองลงในการเรียก WCF ทุกครั้งในลักษณะที่เป็นวัตถุ

เช่นเดียวกับในคำตอบของ Mark Good และ paulwhit เราต้อง subclass IClientMessageInspectorเพื่อฉีดส่วนหัว HTTP ที่กำหนดเองลงในคำขอ WCF อย่างไรก็ตามให้ผู้ตรวจการทั่วไปมีความหลากหลายมากขึ้นโดยการยอมรับพจนานุกรมที่มีส่วนหัวที่เราต้องการเพิ่ม:

public class HttpHeaderMessageInspector : IClientMessageInspector
{
    private Dictionary<string, string> Headers;

    public HttpHeaderMessageInspector(Dictionary<string, string> headers)
    {
        Headers = headers;
    }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        // ensure the request header collection exists
        if (request.Properties.Count == 0 || request.Properties[HttpRequestMessageProperty.Name] == null)
        {
            request.Properties.Add(HttpRequestMessageProperty.Name, new HttpRequestMessageProperty());
        }

        // get the request header collection from the request
        var HeadersCollection = ((HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]).Headers;

        // add our headers
        foreach (var header in Headers) HeadersCollection[header.Key] = header.Value;

        return null;
    }

    // ... other unused interface methods removed for brevity ...
}

เช่นเดียวกับในคำตอบของ Mark Good และ paulwhit เราต้อง subclass IEndpointBehaviorเพื่อฉีดHttpHeaderMessageInspectorเข้าไปในลูกค้า WCF ของเรา

public class AddHttpHeaderMessageEndpointBehavior : IEndpointBehavior
{
    private IClientMessageInspector HttpHeaderMessageInspector;

    public AddHttpHeaderMessageEndpointBehavior(Dictionary<string, string> headers)
    {
        HttpHeaderMessageInspector = new HttpHeaderMessageInspector(headers);
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.ClientMessageInspectors.Add(HttpHeaderMessageInspector);
    }

    // ... other unused interface methods removed for brevity ...
}

ส่วนสุดท้ายที่จำเป็นในการทำให้วิธีการเชิงวัตถุของเราเสร็จสิ้นคือการสร้างคลาสย่อยของไคลเอนต์ที่สร้างขึ้นอัตโนมัติ WCF ของเรา (ฉันใช้คู่มืออ้างอิงบริการเว็บ WCFของ Microsoft เพื่อสร้างไคลเอนต์ WCF)

ในกรณีของฉันฉันต้องแนบรหัส API กับx-api-keyส่วนหัว HTML

คลาสย่อยทำสิ่งต่อไปนี้:

  • เรียกตัวสร้างของคลาสฐานด้วยพารามิเตอร์ที่ต้องการ (ในกรณีของฉัน EndpointConfiguration enum ถูกสร้างขึ้นเพื่อส่งผ่านไปยังนวกรรมิก - บางทีการดำเนินการของคุณจะไม่มีสิ่งนี้)
  • กำหนดส่วนหัวที่ควรแนบกับทุกคำขอ
  • ยึดติดAddHttpHeaderMessageEndpointBehaviorกับEndpointพฤติกรรมของลูกค้า
public class Client : MySoapClient
{
    public Client(string apiKey) : base(EndpointConfiguration.SomeConfiguration)
    {
        var headers = new Dictionary<string, string>
        {
            ["x-api-key"] = apiKey
        };

        var behaviour = new AddHttpHeaderMessageEndpointBehavior(headers);
        Endpoint.EndpointBehaviors.Add(behaviour);
    }
}

ในที่สุดใช้ลูกค้าของคุณ!

var apiKey = 'XXXXXXXXXXXXXXXXXXXXXXXXX';
var client = new Client (apiKey);
var result = client.SomeRequest()

คำขอ HTTP ที่เป็นผลลัพธ์ควรมีส่วนหัว HTTP ของคุณและมีลักษณะดังนี้:

POST http://localhost:8888/api/soap HTTP/1.1
Cache-Control: no-cache, max-age=0
Connection: Keep-Alive
Content-Type: text/xml; charset=utf-8
Accept-Encoding: gzip, deflate
x-api-key: XXXXXXXXXXXXXXXXXXXXXXXXX
SOAPAction: "http://localhost:8888/api/ISoapService/SomeRequest"
Content-Length: 144
Host: localhost:8888

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <SomeRequestxmlns="http://localhost:8888/api/"/>
  </s:Body>
</s:Envelope>

-1

สายไปงานเลี้ยงเล็กน้อย แต่ Juval Lowy กล่าวถึงสถานการณ์ที่แน่นอนนี้ในหนังสือของเขาและห้องสมุดServiceModelEx ที่เกี่ยวข้อง

โดยทั่วไปเขาจะกำหนดความเชี่ยวชาญ ClientBase และ ChannelFactory ที่อนุญาตให้ระบุค่าส่วนหัวที่ปลอดภัยต่อประเภท ฉันขอแนะนำให้ดาวน์โหลดแหล่งข้อมูลและดูที่คลาส HeaderClientBase และ HeaderChannelFactory

จอห์น


1
มันไม่มีอะไรมากนอกจากการส่งเสริมงานของใครบางคน คุณสามารถเพิ่มข้อความที่ตัดตอนมา / อัลกอริทึมที่เกี่ยวข้อง - เช่นตอบคำถาม - หรือเปิดเผยความร่วมมือใด ๆ ที่คุณมี? มิฉะนั้นนี่เป็นเพียงสแปมเพ้อฝัน
คดีฟ้องร้องกองทุนโมนิก้า

ฉันจะบอกว่ามันให้คำตอบกับคนที่ชี้ไปยังวิธีที่พวกเขาอาจไม่ได้รับรู้ ฉันได้รับลิงก์ที่เกี่ยวข้องแล้วเหตุใดฉันจึงต้องเพิ่มอีก มันคือทั้งหมดที่อยู่ในการอ้างอิง และฉันแน่ใจว่า Juval Lowy สามารถอธิบายได้ดีกว่าที่ฉันทำได้ :-) สำหรับการติดต่อของฉัน - ฉันซื้อหนังสือเล่มนี้! แค่นั้นแหละ. ฉันไม่เคยเจอ Mr Lowy มาก่อน แต่ฉันมั่นใจว่าเขาเป็นคนที่ยอดเยี่ยมมาก รู้มากเกี่ยวกับ WCF เห็นได้ชัด ;-)
BrizzleOwl

คุณควรเพิ่มมากขึ้นเนื่องจากคุณอ่านวิธีการตอบก่อนที่จะตอบและคุณสังเกตว่าส่วนที่ระบุว่า "อ้างอิงส่วนที่เกี่ยวข้องที่สุดของลิงค์สำคัญเสมอในกรณีที่ไซต์เป้าหมายไม่สามารถเข้าถึงได้หรือออฟไลน์ถาวร" ความร่วมมือของคุณไม่สำคัญ คุณภาพของคำตอบเท่านั้น
คดีฟ้องร้องกองทุนโมนิก้า

ละเอียด. ฉันไม่ได้อยู่ในนั้น - คุณอาจบอกได้จากคะแนนของฉัน! แค่คิดว่ามันอาจเป็นตัวชี้ที่มีประโยชน์
BrizzleOwl

1
ฉันไม่ได้บอกว่ามันเป็นตัวชี้ที่ไม่ดี ฉันกำลังพูดแบบนั้นมันไม่ใช่คำตอบที่ดี มันอาจช่วยคนได้เป็นอย่างดีและนั่นก็เป็นสิ่งที่ดี แต่คำตอบจะดีกว่าถ้าคุณสามารถอธิบายวิธีที่เขาใช้แทนที่จะให้คำอธิบายสั้น ๆ เกี่ยวกับชั้นเรียนที่เกี่ยวข้อง ด้วยวิธีนี้ในโอกาสที่เว็บไซต์ไม่สามารถเข้าถึงได้ไม่ว่าด้วยเหตุผลใด - คำตอบของคุณยังคงช่วย
คดีฟ้องร้องกองทุนโมนิก้า
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.