Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Uygulamanız, ön planda değilken ağ iletişimini sürdürmek için arka plan görevlerini ve bu iki seçenekten birini kullanabilir.
- Soket aracısı. Uygulamanız uzun süreli bağlantılar için yuvalar kullanıyorsa, ön plandan ayrıldığında bir yuvanın sahipliğini bir sistem yuva aracısı için devredebilir. Ardından aracı, trafik sokete ulaştığında uygulamanızı etkinleştirir; soketin sahipliğini yeniden uygulamanıza devreder; ardından uygulamanız da gelen trafiği işler.
- Kontrol kanalı tetikleyicileri.
Arka plan görevlerinde ağ işlemleri gerçekleştirme
- Bir paket alındığında ve kısa süreli bir görev gerçekleştirmeniz gerektiğinde arka plan görevini etkinleştirmek için SocketActivityTrigger kullanın. Görevi gerçekleştirdikten sonra, güç tasarrufu sağlamak için arka plan görevi sonlandırılmalıdır.
- Bir paket alındığında ve uzun ömürlü bir görev gerçekleştirmeniz gerektiğinde arka plan görevini etkinleştirmek için ControlChannelTrigger kullanın.
Ağ ile ilgili koşullar ve bayraklar
- InternetAvailable koşulunu arka plan görevinize BackgroundTaskBuilder.AddCondition ekleyerek ağ yığını çalışana kadar arka plan görevini tetikleme işlemini geciktirin. Arka plan görevi ağ çalışmayana kadar yürütülmeyeceği için bu koşul güç tasarrufu sağlar. Bu koşul gerçek zamanlı etkinleştirme sağlamaz.
Kullandığınız tetikleyiciden bağımsız olarak, arka plan görevi çalışırken ağın çalışır durumda kaldığından emin olmak için arka plan görevinizde IsNetworkRequested değerini ayarlayın. Bu, arka plan görev altyapısına, cihaz Bağlı Bekleme moduna girmiş olsa bile görev yürütülürken ağı çalışır durumda tutmasını söyler. Arka plan göreviniz IsNetworkRequested kullanmıyorsa, arka plan göreviniz Bağlı Bekleme modundayken (örneğin, bir telefonun ekranı kapalı olduğunda) ağa erişemez.
Soket aracısı ve SocketActivityTrigger
Uygulamanız DatagramSocket, StreamSocket veya StreamSocketListener bağlantıları kullanıyorsa, uygulamanız için trafik ön planda olmadığında trafik geldiğinde bildirim almak üzere SocketActivityTrigger ve yuva aracısı kullanmanız gerekir.
Uygulamanız etkin olmadığında bir yuvaya alınan verileri alabilmesi ve işleyebilmesi için, uygulamanızın başlangıçta tek seferlik bir kurulum gerçekleştirmesi ve ardından etkin olmayan bir duruma geçerken yuva sahipliğini yuva aracısına aktarması gerekir.
Tek seferlik kurulum adımları tetikleyici oluşturmak, tetikleyici için bir arka plan görevi kaydetmek ve yuva aracısı için yuvayı etkinleştirmektir:
- Bir SocketActivityTrigger oluşturun ve alınan paketi işlemek için kodunuz olarak ayarlanmış TaskEntryPoint parametresiyle tetikleyici için bir arka plan görevi kaydedin.
var socketTaskBuilder = new BackgroundTaskBuilder();
socketTaskBuilder.Name = _backgroundTaskName;
socketTaskBuilder.TaskEntryPoint = _backgroundTaskEntryPoint;
var trigger = new SocketActivityTrigger();
socketTaskBuilder.SetTrigger(trigger);
_task = socketTaskBuilder.Register();
- Yuvayı bağlamadan önce yuvada EnableTransferOwnership öğesini çağırın.
_tcpListener = new StreamSocketListener();
// Note that EnableTransferOwnership() should be called before bind,
// so that tcpip keeps required state for the socket to enable connected
// standby action. Background task Id is taken as a parameter to tie wake pattern
// to a specific background task.
_tcpListener.EnableTransferOwnership(_task.TaskId, SocketActivityConnectedStandbyAction.Wake);
_tcpListener.ConnectionReceived += OnConnectionReceived;
await _tcpListener.BindServiceNameAsync("my-service-name");
Soketiniz doğru şekilde yapılandırıldıktan sonra, uygulamanız askıya alınmak üzereyken, onu bir soket aracısına aktarmak için soket üzerinde TransferOwnership yöntemini çağırın. Aracı hizmet soketi izler ve veri alındığında arka plan görevinizi etkinleştirir. Aşağıdaki örnek, StreamSocketListener yuvaları için aktarımı gerçekleştirmek için bir TransferOwnership yardımcı programı işlevi içerir. (Farklı yuva türlerinin her birinin kendi TransferOwnership yöntemi olduğuna dikkat edin, bu nedenle sahipliğini aktardığınız yuva için uygun yöntemi çağırmanız gerekir. Kodunuz büyük olasılıkla kullandığınız her yuva türü için bir uygulama içeren aşırı yüklenmiş bir TransferOwnership yardımcısı içerebilir, böylece OnSuspending kodunun okunması kolay kalır.)
Bir uygulama, bir soketin sahipliğini bir soket aracısına aktarır ve aşağıdaki yöntemlerden uygun olanını kullanarak arka plan görevi kimliğini iletir:
- DatagramSocket üzerindeki TransferOwnership yöntemlerinden biri.
- StreamSocket üzerindeki TransferOwnership yöntemlerinden biri.
- StreamSocketListener üzerindeki TransferOwnership yöntemlerinden biri.
// declare int _transferOwnershipCount as a field.
private async void TransferOwnership(StreamSocketListener tcpListener)
{
await tcpListener.CancelIOAsync();
var dataWriter = new DataWriter();
++_transferOwnershipCount;
dataWriter.WriteInt32(_transferOwnershipCount);
var context = new SocketActivityContext(dataWriter.DetachBuffer());
tcpListener.TransferOwnership(_socketId, context);
}
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
TransferOwnership(_tcpListener);
deferral.Complete();
}
Arka plan görevinizin olay işleyicisinde:
- İlk olarak, olayı eşzamansız yöntemlerle işleyebilmeniz için arka plan görevi için bir erteleme alın.
var deferral = taskInstance.GetDeferral();
- Ardından, olay bağımsız değişkenlerinden SocketActivityTriggerDetails öğesini çıkarın ve olayın neden tetiklendiğini bulun:
var details = taskInstance.TriggerDetails as SocketActivityTriggerDetails;
var socketInformation = details.SocketInformation;
switch (details.Reason)
- Olay yuva etkinliği nedeniyle tetiklendiyse, yuvada bir DataReader oluşturun, okuyucuyu zaman uyumsuz olarak yükleyin ve ardından verileri uygulamanızın tasarımına göre kullanın. Daha sonraki soket etkinlikleri hakkında yeniden bildirim alabilmek için, soketin sahipliğini soket aracısına geri devretmeniz gerektiğini unutmayın.
Aşağıdaki örnekte, soket üzerinden alınan metin bir toast bildiriminde görüntülenir.
case SocketActivityTriggerReason.SocketActivity:
var socket = socketInformation.StreamSocket;
DataReader reader = new DataReader(socket.InputStream);
reader.InputStreamOptions = InputStreamOptions.Partial;
await reader.LoadAsync(250);
var dataString = reader.ReadString(reader.UnconsumedBufferLength);
ShowToast(dataString);
socket.TransferOwnership(socketInformation.Id); /* Important! */
break;
- Etkin tutma süreölçerinin süresi dolduğu için olay tetiklendiyse, yuvayı canlı tutmak ve etkin tutma zamanlayıcısını yeniden başlatmak için kodunuz yuva üzerinden bazı veriler göndermelidir. Soketin sahipliğini, daha fazla olay bildirimi alabilmek için socket broker'a geri vermek önemlidir:
case SocketActivityTriggerReason.KeepAliveTimerExpired:
socket = socketInformation.StreamSocket;
DataWriter writer = new DataWriter(socket.OutputStream);
writer.WriteBytes(Encoding.UTF8.GetBytes("Keep alive"));
await writer.StoreAsync();
writer.DetachStream();
writer.Dispose();
socket.TransferOwnership(socketInformation.Id); /* Important! */
break;
- Olay, soket kapatıldığı için tetiklendiyse soketi yeniden kurun ve yeni soketi oluşturduktan sonra sahipliğini soket aracısına devrettiğinizden emin olun. Bu örnekte, ana bilgisayar adı ve bağlantı noktası yerel ayarlarda depolanır, böylece yeni bir yuva bağlantısı kurmak için kullanılabilirler:
case SocketActivityTriggerReason.SocketClosed:
socket = new StreamSocket();
socket.EnableTransferOwnership(taskInstance.Task.TaskId, SocketActivityConnectedStandbyAction.Wake);
if (ApplicationData.Current.LocalSettings.Values["hostname"] == null)
{
break;
}
var hostname = (String)ApplicationData.Current.LocalSettings.Values["hostname"];
var port = (String)ApplicationData.Current.LocalSettings.Values["port"];
await socket.ConnectAsync(new HostName(hostname), port);
socket.TransferOwnership(socketId);
break;
- Olay bildirimini işlemeyi tamamladıktan sonra erteleme işleminizi tamamlamayı unutmayın:
deferral.Complete();
SocketActivityTrigger ve yuva aracısı kullanımını gösteren eksiksiz bir örnek için bkz. SocketActivityStreamSocket örneği. Soketin başlatılması Scenario1_Connect.xaml.cs dosyasında gerçekleştirilir ve arka plan görevinin gerçekleştirilmesi SocketActivityTask.cs dosyasında yer alır.
Örneğin, bu konuda açıklandığı gibi bunu yapmak için OnSuspending olay işleyicisini kullanmak yerine, yeni bir yuva oluşturur oluşturmaz veya mevcut bir yuvayı edinir edinmez TransferOwnership çağrısı yaptığını muhtemelen fark edeceksiniz. Bunun nedeni, örneğin SocketActivityTrigger'ı göstermeye odaklanması ve çalışırken soketi başka herhangi bir etkinlik için kullanmamasıdır. Uygulamanız büyük olasılıkla daha karmaşık olacaktır ve TransferOwnership'in ne zaman çağrılacağını belirlemek için OnSuspending kullanmalıdır.
Kontrol kanalı tetikleyicileri
İlk olarak, denetim kanalı tetikleyicilerini (CCT) uygun şekilde kullandığınızdan emin olun. DatagramSocket, StreamSocket veya StreamSocketListener bağlantıları kullanıyorsanız SocketActivityTrigger kullanmanızı öneririz. StreamSocket için CCT'leri kullanabilirsiniz, ancak bunlar daha fazla kaynak kullanır ve Bağlı Bekleme modunda çalışmayabilir.
WebSockets, IXMLHTTPRequest2, System.Net.Http.HttpClient veya Windows kullanıyorsanız. Web.Http.HttpClient, ardından ControlChannelTrigger kullanmanız gerekir.
WebSockets ile ControlChannelTrigger
Important
Bu bölümde açıklanan özellik (WebSockets ile ControlChannelTrigger), Windows SDK sürüm 10.0.15063.0 ve sonraki sürümlerde desteklenir.
ControlChannelTrigger ile MessageWebSocket veya StreamWebSocket kullanılırken dikkat edilmesi gereken bazı özel noktalar geçerlidir. ControlChannelTrigger ile MessageWebSocket veya StreamWebSocket kullanılırken izlenmesi gereken bazı aktarıma özgü kullanım desenleri ve en iyi yöntemler vardır. Buna ek olarak, bu önemli noktalar StreamWebSocket'te paket alma isteklerinin işlenme şeklini etkiler. MessageWebSocket'te paket alma istekleri etkilenmez.
ControlChannelTrigger ile MessageWebSocket veya StreamWebSocket kullanılırken aşağıdaki kullanım düzenleri ve en iyi yöntemler izlenmelidir:
- Bekleyen bir soket alma işlemi her zaman başlatılmış durumda tutulmalıdır. Anında iletme bildirimi görevlerinin gerçekleşmesine izin vermek için bu gereklidir.
- WebSocket protokolü, canlı tutma iletileri için standart bir model tanımlar. WebSocketKeepAlive sınıfı, istemci tarafından başlatılan WebSocket protokolü etkin tutma iletilerini sunucuya gönderebilir. WebSocketKeepAlive sınıfı, uygulama tarafından bir KeepAliveTrigger için TaskEntryPoint olarak kaydedilmelidir.
Bazı özel noktalar StreamWebSocket'te paket alma isteklerinin işlenme şeklini etkiler. Özellikle, ControlChannelTrigger ile StreamWebSocket kullanırken, uygulamanızın C# ve VB.NET veya C++ içindeki Görevler'de await modeli yerine okumaları işlemek için ham bir zaman uyumsuz desen kullanması gerekir. Temel asenkron örüntü, bu bölümün ilerleyen kısımlarında bir kod örneğiyle gösterilmektedir.
Ham async düzeninin kullanılması, Windows'un ControlChannelTrigger için arka plan görevindeki IBackgroundTask.Run yöntemini, alma işlemi tamamlama geri çağrısının dönüşüyle eşzamanlamasına olanak tanır. Run yöntemi, geri çağırma tamamlandıktan sonra çağrılır. Bu, Çalıştır yöntemi çağrılmadan önce uygulamanın verileri/hataları aldığından emin olunmasını sağlar.
Şunu unutmamak önemlidir: uygulama, denetimi tamamlama geri çağırmasından geri vermeden önce başka bir okuma isteği göndermelidir. Yukarıda açıklanan eşitlemeyi bozan DataReader'ınMessageWebSocket veya StreamWebSocket aktarımıyla doğrudan kullanılamadığını da unutmayın. DataReader.LoadAsync yönteminin doğrudan aktarım üzerinde kullanılması desteklenmez. Bunun yerine, StreamWebSocket.InputStream özelliğinde IInputStream.ReadAsync yöntemi tarafından döndürülen IBuffer daha sonra daha fazla işlem için DataReader.FromBuffer yöntemine geçirilebilir.
Aşağıdaki örnek, StreamWebSocket üzerinde okuma işlemlerini işlemek için ham bir zaman uyumsuz desenin nasıl kullanılacağını gösterir.
void PostSocketRead(int length)
{
try
{
var readBuf = new Windows.Storage.Streams.Buffer((uint)length);
var readOp = socket.InputStream.ReadAsync(readBuf, (uint)length, InputStreamOptions.Partial);
readOp.Completed = (IAsyncOperationWithProgress<IBuffer, uint>
asyncAction, AsyncStatus asyncStatus) =>
{
switch (asyncStatus)
{
case AsyncStatus.Completed:
case AsyncStatus.Error:
try
{
// GetResults in AsyncStatus::Error is called as it throws a user friendly error string.
IBuffer localBuf = asyncAction.GetResults();
uint bytesRead = localBuf.Length;
readPacket = DataReader.FromBuffer(localBuf);
OnDataReadCompletion(bytesRead, readPacket);
}
catch (Exception exp)
{
Diag.DebugPrint("Read operation failed: " + exp.Message);
}
break;
case AsyncStatus.Canceled:
// Read is not cancelled in this sample.
break;
}
};
}
catch (Exception exp)
{
Diag.DebugPrint("failed to post a read failed with error: " + exp.Message);
}
}
Okuma tamamlama işleyicisinin, ControlChannelTrigger için arka plan görevindeki IBackgroundTask.Run yöntemi çağrılmadan önce çalıştırılması garanti edilir. Windows, bir uygulamanın okuma tamamlama geri çağrısından çıkmasını beklemek için dahili bir senkronizasyon mekanizmasına sahiptir. Uygulama genellikle, MessageWebSocket'ten veya StreamWebSocket'ten gelen verileri ya da hatayı okuma tamamlanma geri çağırma işlevinde hızla işler. İletinin kendisi IBackgroundTask.Run yöntemi bağlamında işlenir. Aşağıdaki örnekte bu nokta, okuma tamamlama işleyicisinin iletiyi eklediği ve arka plan görevinin daha sonra işlediği bir ileti kuyruğu kullanılarak gösterilmiştir.
Aşağıdaki örnek, StreamWebSocket üzerindeki okuma işlemlerini işlemek için ham zaman uyumsuz düzenle kullanılacak okuma tamamlama işleyicisini gösterir.
public void OnDataReadCompletion(uint bytesRead, DataReader readPacket)
{
if (readPacket == null)
{
Diag.DebugPrint("DataReader is null");
// Ideally when read completion returns error,
// apps should be resilient and try to
// recover if there is an error by posting another recv
// after creating a new transport, if required.
return;
}
uint buffLen = readPacket.UnconsumedBufferLength;
Diag.DebugPrint("bytesRead: " + bytesRead + ", unconsumedbufflength: " + buffLen);
// check if buffLen is 0 and treat that as fatal error.
if (buffLen == 0)
{
Diag.DebugPrint("Received zero bytes from the socket. Server must have closed the connection.");
Diag.DebugPrint("Try disconnecting and reconnecting to the server");
return;
}
// Perform minimal processing in the completion
string message = readPacket.ReadString(buffLen);
Diag.DebugPrint("Received Buffer : " + message);
// Enqueue the message received to a queue that the push notify
// task will pick up.
AppContext.messageQueue.Enqueue(message);
// Post another receive to ensure future push notifications.
PostSocketRead(MAX_BUFFER_LENGTH);
}
Websockets için bir diğer ayrıntı, bağlantıyı canlı tutma işleyicisidir. WebSocket protokolü, canlı tutma iletileri için standart bir model tanımlar.
MessageWebSocket veya StreamWebSocket kullanırken, uygulamanın sabitlenmemiş olmasına ve sunucuya (uzak uç nokta) düzenli aralıklarla canlı tutma iletileri göndermesine izin vermek için bir WebSocketKeepAlive sınıf örneğini Bir KeepAliveTrigger için TaskEntryPoint olarak kaydedin. Bu, hem arka plan kayıt uygulama kodunun hem de paket bildiriminin bir parçası olarak yapılmalıdır.
bu görev giriş noktası Windows. Sockets.WebSocketKeepAlive öğesinin iki yerde belirtilmesi gerekir:
- Kaynak kodunda KeepAliveTrigger tetikleyicisi oluştururken (aşağıdaki örniğe bakın).
- keepalive arka plan görevi bildirimi için uygulama paketi bildirim dosyasında.
Aşağıdaki örnek, bir uygulama bildirgesindeki <Application> öğesinin altına bir ağ tetikleyici bildirimi ve bir canlı tutma tetikleyicisi ekler.
<Extensions>
<Extension Category="windows.backgroundTasks"
Executable="$targetnametoken$.exe"
EntryPoint="Background.PushNotifyTask">
<BackgroundTasks>
<Task Type="controlChannel" />
</BackgroundTasks>
</Extension>
<Extension Category="windows.backgroundTasks"
Executable="$targetnametoken$.exe"
EntryPoint="Windows.Networking.Sockets.WebSocketKeepAlive">
<BackgroundTasks>
<Task Type="controlChannel" />
</BackgroundTasks>
</Extension>
</Extensions>
Bir uygulama, ControlChannelTrigger bağlamında await deyimini ve StreamWebSocket, MessageWebSocket veya StreamSocket üzerinde gerçekleştirilen zaman uyumsuz bir işlemi kullanırken son derece dikkatli olmalıdır.
Aşağıdaki örnek, anında iletme bildirimleri ve StreamWebSocket üzerinde WebSocket canlı tutma işlemleri için ControlChannelTrigger'ı kaydeder.
private bool RegisterWithControlChannelTrigger(string serverUri)
{
// Make sure the objects are created in a system thread
// Demonstrate the core registration path
// Wait for the entire operation to complete before returning from this method.
// The transport setup routine can be triggered by user control, by network state change
// or by keepalive task
Task<bool> registerTask = RegisterWithCCTHelper(serverUri);
return registerTask.Result;
}
async Task<bool> RegisterWithCCTHelper(string serverUri)
{
bool result = false;
socket = new StreamWebSocket();
// Specify the keepalive interval expected by the server for this app
// in order of minutes.
const int serverKeepAliveInterval = 30;
// Specify the channelId string to differentiate this
// channel instance from any other channel instance.
// When background task fires, the channel object is provided
// as context and the channel id can be used to adapt the behavior
// of the app as required.
const string channelId = "channelOne";
// For websockets, the system does the keepalive on behalf of the app
// But the app still needs to specify this well known keepalive task.
// This should be done here in the background registration as well
// as in the package manifest.
const string WebSocketKeepAliveTask = "Windows.Networking.Sockets.WebSocketKeepAlive";
// Try creating the controlchanneltrigger if this has not been already
// created and stored in the property bag.
ControlChannelTriggerStatus status;
// Create the ControlChannelTrigger object and request a hardware slot for this app.
// If the app is not on LockScreen, then the ControlChannelTrigger constructor will
// fail right away.
try
{
channel = new ControlChannelTrigger(channelId, serverKeepAliveInterval,
ControlChannelTriggerResourceType.RequestHardwareSlot);
}
catch (UnauthorizedAccessException exp)
{
Diag.DebugPrint("Is the app on lockscreen? " + exp.Message);
return result;
}
Uri serverUriInstance;
try
{
serverUriInstance = new Uri(serverUri);
}
catch (Exception exp)
{
Diag.DebugPrint("Error creating URI: " + exp.Message);
return result;
}
// Register the apps background task with the trigger for keepalive.
var keepAliveBuilder = new BackgroundTaskBuilder();
keepAliveBuilder.Name = "KeepaliveTaskForChannelOne";
keepAliveBuilder.TaskEntryPoint = WebSocketKeepAliveTask;
keepAliveBuilder.SetTrigger(channel.KeepAliveTrigger);
keepAliveBuilder.Register();
// Register the apps background task with the trigger for push notification task.
var pushNotifyBuilder = new BackgroundTaskBuilder();
pushNotifyBuilder.Name = "PushNotificationTaskForChannelOne";
pushNotifyBuilder.TaskEntryPoint = "Background.PushNotifyTask";
pushNotifyBuilder.SetTrigger(channel.PushNotificationTrigger);
pushNotifyBuilder.Register();
// Tie the transport method to the ControlChannelTrigger object to push enable it.
// Note that if the transport' s TCP connection is broken at a later point of time,
// the ControlChannelTrigger object can be reused to plug in a new transport by
// calling UsingTransport API again.
try
{
channel.UsingTransport(socket);
// Connect the socket
//
// If connect fails or times out it will throw exception.
// ConnectAsync can also fail if hardware slot was requested
// but none are available
await socket.ConnectAsync(serverUriInstance);
// Call WaitForPushEnabled API to make sure the TCP connection has
// been established, which will mean that the OS will have allocated
// any hardware slot for this TCP connection.
//
// In this sample, the ControlChannelTrigger object was created by
// explicitly requesting a hardware slot.
//
// On systems that without connected standby, if app requests hardware slot as above,
// the system will fallback to a software slot automatically.
//
// On systems that support connected standby,, if no hardware slot is available, then app
// can request a software slot by re-creating the ControlChannelTrigger object.
status = channel.WaitForPushEnabled();
if (status != ControlChannelTriggerStatus.HardwareSlotAllocated
&& status != ControlChannelTriggerStatus.SoftwareSlotAllocated)
{
throw new Exception(string.Format("Neither hardware nor software slot could be allocated. ChannelStatus is {0}", status.ToString()));
}
// Store the objects created in the property bag for later use.
CoreApplication.Properties.Remove(channel.ControlChannelTriggerId);
var appContext = new AppContext(this, socket, channel, channel.ControlChannelTriggerId);
((IDictionary<string, object>)CoreApplication.Properties).Add(channel.ControlChannelTriggerId, appContext);
result = true;
// Almost done. Post a read since we are using streamwebsocket
// to allow push notifications to be received.
PostSocketRead(MAX_BUFFER_LENGTH);
}
catch (Exception exp)
{
Diag.DebugPrint("RegisterWithCCTHelper Task failed with: " + exp.Message);
// Exceptions may be thrown for example if the application has not
// registered the background task class id for using real time communications
// broker in the package manifest.
}
return result;
}
MessageWebSocket veya StreamWebSocket'iControlChannelTrigger ile kullanma hakkında daha fazla bilgi için bkz. ControlChannelTrigger StreamWebSocket örneği.
HttpClient ile ControlChannelTrigger
ControlChannelTrigger ile HttpClient kullanılırken dikkat edilmesi gereken bazı özel noktalar geçerlidir. ControlChannelTrigger ile HttpClient kullanılırken izlenmesi gereken bazı aktarıma özgü kullanım desenleri ve en iyi yöntemler vardır. Buna ek olarak, bu önemli noktalar HttpClient üzerinde paket alma isteklerinin işlenme şeklini etkiler.
Not SSL kullanan HttpClient şu anda ağ tetikleyicisi özelliği ve ControlChannelTrigger kullanılarak desteklenmiyor. ControlChannelTrigger ile HttpClient kullanılırken aşağıdaki kullanım düzenleri ve en iyi yöntemler izlenmelidir:
- Uygulamanın, isteği belirli bir URI'ye göndermeden önce System.Net.Http ad alanında HttpClient veya HttpClientHandler nesnesinde çeşitli özellikler ve üst bilgiler ayarlaması gerekebilir.
- ControlChannelTrigger ile kullanılacak HttpClient aktarımını oluşturmadan önce bir uygulamanın taşımayı düzgün bir şekilde test etmek ve ayarlamak için ilk istekte bulunma ihtiyacı duyması gerekebilir. Uygulama aktarım işleminin düzgün şekilde ayarlanabileceğini belirledikten sonra, bir HttpClient nesnesi ControlChannelTrigger nesnesiyle kullanılan aktarım nesnesi olarak yapılandırılabilir. Bu süreç, bazı senaryoların taşıma katmanı üzerinden kurulan bağlantıyı bozmasını önleyecek şekilde tasarlanmıştır. Sertifikayla SSL kullanıldığında, bir uygulama PIN girişi için bir iletişim kutusunun görüntülenmesini veya aralarından seçim yapabileceğiniz birden çok sertifika olup olmadığını gerektirebilir. Proxy kimlik doğrulaması ve sunucu kimlik doğrulaması gerekebilir. Ara sunucu veya sunucu kimlik doğrulamasının süresi dolarsa bağlantı kapatılabilir. Bir uygulamanın bu kimlik doğrulaması süre sonu sorunlarıyla başa çıkma yollarından biri zamanlayıcı ayarlamaktır. HTTP yeniden yönlendirmesi gerektiğinde, ikinci bağlantının güvenilir bir şekilde kurulabileceği garanti edilmemektedir. İlk test isteği, uygulamanın ControlChannelTrigger nesnesiyle aktarım olarak HttpClient nesnesini kullanmadan önce en up-to-date yeniden yönlendirilen URL'yi kullanabilmesini sağlar.
Diğer ağ aktarımlarından farklı olarak, HttpClient nesnesi doğrudan ControlChannelTrigger nesnesininUsingTransport yöntemine geçirilemez. Bunun yerine, bir HttpRequestMessage nesnesi, HttpClient nesnesi ve ControlChannelTrigger ile kullanılmak üzere özel olarak oluşturulmalıdır. HttpRequestMessage nesnesi RtcRequestFactory.Create yöntemi kullanılarak oluşturulur. Oluşturulan HttpRequestMessage nesnesi daha sonra UsingTransport yöntemine geçirilir.
Aşağıdaki örnekte, HttpClient nesnesi ve ControlChannelTrigger ile kullanmak üzere birHttpRequestMessage nesnesinin nasıl oluşturacakları gösterilmektedir.
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Windows.Networking.Sockets;
public HttpRequestMessage httpRequest;
public HttpClient httpClient;
public HttpRequestMessage httpRequest;
public ControlChannelTrigger channel;
public Uri serverUri;
private void SetupHttpRequestAndSendToHttpServer()
{
try
{
// For HTTP based transports that use the RTC broker, whenever we send next request, we will abort the earlier
// outstanding http request and start new one.
// For example in case when http server is taking longer to reply, and keep alive trigger is fired in-between
// then keep alive task will abort outstanding http request and start a new request which should be finished
// before next keep alive task is triggered.
if (httpRequest != null)
{
httpRequest.Dispose();
}
httpRequest = RtcRequestFactory.Create(HttpMethod.Get, serverUri);
SendHttpRequest();
}
catch (Exception e)
{
Diag.DebugPrint("Connect failed with: " + e.ToString());
throw;
}
}
Bazı özel noktalar, yanıt almayı başlatmak için HttpClient üzerinde HTTP istekleri gönderme isteklerinin işlenme biçimini etkiler. Özellikle, ControlChannelTrigger ile bir HttpClient kullanırken uygulamanızın await modeli yerine göndermeleri işlemek için bir Görev kullanması gerekir.
HttpClient kullanıldığında, ControlChannelTrigger için arka plan görevindeki IBackgroundTask.Run yöntemi ile alma tamamlama geri çağırma işlevinin dönüşü arasında eşzamanlama yoktur. Bu nedenle uygulama, Çalıştır yönteminde yalnızca engelleyici HttpResponseMessage tekniğini kullanabilir ve yanıtın tamamı alınana kadar bekleyebilir.
HttpClient'ıControlChannelTrigger ile kullanmak StreamSocket, MessageWebSocket veya StreamWebSocket aktarımlarından önemli ölçüde farklıdır. HttpClient alma geri araması, HttpClient kodundan bu yana uygulamaya bir Görev aracılığıyla teslim edilir. Bu, ControlChannelTrigger anında iletme bildirimi görevinin, veri ya da hata uygulamaya iletilir iletilmez tetikleneceği anlamına gelir. Aşağıdaki örnekte kod, HttpClient.SendAsync yöntemi tarafından döndürülen responseTask’i, anlık bildirim görevinin alıp satır içinde işleyeceği genel depolamaya kaydeder.
Aşağıdaki örnek, ControlChannelTrigger ile kullanıldığında HttpClient üzerinde gönderme isteklerinin nasıl işleneceğini gösterir.
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Windows.Networking.Sockets;
private void SendHttpRequest()
{
if (httpRequest == null)
{
throw new Exception("HttpRequest object is null");
}
// Tie the transport method to the controlchanneltrigger object to push enable it.
// Note that if the transport' s TCP connection is broken at a later point of time,
// the controlchanneltrigger object can be reused to plugin a new transport by
// calling UsingTransport API again.
channel.UsingTransport(httpRequest);
// Call the SendAsync function to kick start the TCP connection establishment
// process for this http request.
Task<HttpResponseMessage> httpResponseTask = httpClient.SendAsync(httpRequest);
// Call WaitForPushEnabled API to make sure the TCP connection has been established,
// which will mean that the OS will have allocated any hardware slot for this TCP connection.
ControlChannelTriggerStatus status = channel.WaitForPushEnabled();
Diag.DebugPrint("WaitForPushEnabled() completed with status: " + status);
if (status != ControlChannelTriggerStatus.HardwareSlotAllocated
&& status != ControlChannelTriggerStatus.SoftwareSlotAllocated)
{
throw new Exception("Hardware/Software slot not allocated");
}
// The HttpClient receive callback is delivered via a Task to the app.
// The notification task will fire as soon as the data or error is dispatched
// Enqueue the responseTask returned by httpClient.sendAsync
// into a queue that the push notify task will pick up and process inline.
AppContext.messageQueue.Enqueue(httpResponseTask);
}
Aşağıdaki örnekte, ControlChannelTrigger ile kullanıldığında HttpClient üzerinde alınan yanıtların nasıl okunduğu gösterilmektedir.
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public string ReadResponse(Task<HttpResponseMessage> httpResponseTask)
{
string message = null;
try
{
if (httpResponseTask.IsCanceled || httpResponseTask.IsFaulted)
{
Diag.DebugPrint("Task is cancelled or has failed");
return message;
}
// We' ll wait until we got the whole response.
// This is the only supported scenario for HttpClient for ControlChannelTrigger.
HttpResponseMessage httpResponse = httpResponseTask.Result;
if (httpResponse == null || httpResponse.Content == null)
{
Diag.DebugPrint("Cannot read from httpresponse, as either httpResponse or its content is null. try to reset connection.");
}
else
{
// This is likely being processed in the context of a background task and so
// synchronously read the Content' s results inline so that the Toast can be shown.
// before we exit the Run method.
message = httpResponse.Content.ReadAsStringAsync().Result;
}
}
catch (Exception exp)
{
Diag.DebugPrint("Failed to read from httpresponse with error: " + exp.ToString());
}
return message;
}
HttpClient'ıControlChannelTrigger ile kullanma hakkında daha fazla bilgi için bkz. ControlChannelTrigger HttpClient örneği.
IXMLHttpRequest2 ile ControlChannelTrigger
ControlChannelTrigger ile IXMLHTTPRequest2 kullanılırken dikkat edilmesi gereken bazı önemli noktalar vardır. ControlChannelTrigger ile IXMLHTTPRequest2 kullanılırken izlenmesi gereken bazı aktarıma özgü kullanım desenleri ve en iyi yöntemler vardır. ControlChannelTrigger'ın kullanılması, IXMLHTTPRequest2 üzerinde HTTP istekleri gönderme veya alma isteklerinin işlenme biçimini etkilemez.
ControlChannelTrigger ile IXMLHTTPRequest2 kullanırken kullanım desenleri ve en iyi yöntemler
- Aktarım olarak kullanılan bir IXMLHTTPRequest2 nesnesi yalnızca bir istek/yanıt ömrüne sahiptir. ControlChannelTrigger nesnesiyle kullanıldığında, ControlChannelTrigger nesnesini bir kez oluşturup ayarlamak ve ardından her seferinde yeni bir IXMLHTTPRequest2 nesnesiyle ilişkilendirildiğinde Tekrar tekrar UsingTransport yöntemini çağırmak uygundur. Uygulamanın ayrılan kaynak sınırlarını aşmadığından emin olmak için yeni bir IXMLHTTPRequest2 nesnesi sağlamadan önce uygulamanın önceki IXMLHTTPRequest2 nesnesini silmesi gerekir.
- Uygulamanın Send yöntemini çağırmadan önce HTTP aktarımını ayarlamak için SetProperty ve SetRequestHeader yöntemlerini çağırması gerekebilir.
- ControlChannelTrigger ile kullanılacak taşımayı oluşturmadan önce bir uygulamanın taşımayı test etmek ve ayarlamak için ilk Gönderme isteğine ihtiyaç duyması gerekebilir. Uygulama aktarım işleminin düzgün ayarlandığını belirledikten sonra , IXMLHTTPRequest2 nesnesi ControlChannelTrigger ile kullanılan aktarım nesnesi olarak yapılandırılabilir. Bu süreç, bazı senaryoların taşıma katmanı üzerinden kurulan bağlantıyı bozmasını önlemek için tasarlanmıştır. Sertifikayla SSL kullanıldığında, bir uygulama PIN girişi için bir iletişim kutusunun görüntülenmesini veya aralarından seçim yapabileceğiniz birden çok sertifika olup olmadığını gerektirebilir. Proxy kimlik doğrulaması ve sunucu kimlik doğrulaması gerekebilir. Ara sunucu veya sunucu kimlik doğrulamasının süresi dolarsa bağlantı kapatılabilir. Bir uygulamanın bu kimlik doğrulaması süre sonu sorunlarıyla başa çıkma yollarından biri zamanlayıcı ayarlamaktır. HTTP yeniden yönlendirmesi gerektiğinde, ikinci bağlantının güvenilir bir şekilde kurulabileceği garanti edilmemektedir. İlk test isteği, uygulamanın ControlChannelTrigger nesnesiyle taşıyıcı olarak IXMLHTTPRequest2 nesnesini kullanmadan önce en güncel yönlendirilmiş URL’yi kullanabilmesini sağlar.
IXMLHTTPRequest2'yiControlChannelTrigger ile kullanma hakkında daha fazla bilgi için bkz. IXML ile ControlChannelTriggerHTTPRequest2 örneği.
Önemli API'ler
Windows developer