You are here

Feed aggregator

Rules Extensions - Getting Started

MSDN Blogs - Mon, 02/08/2016 - 17:12
When working with FIM / MIM you have the option to add custom rules extensions either to the Entire Metaverse or to a specific MA (Management Agent) In this series of "Rules Extensions" Blog post we will focus on Management Agent Extension. In the Synchronization Server click on the MA you wish to create the Extension for and right click on the Management Agent Click on Create Extension Projects Select Rules Extension Select the Programming Language you wish to...(read more)

Free ebook: Introducing Windows 10 for IT Professionals, Technical Overview

MSDN Blogs - Mon, 02/08/2016 - 11:15

We’re happy to announce the release of our newest free ebook, Introducing Windows 10 for IT Professionals, Technical Overview (ISBN 9780735696976), by Ed Bott.

Mobi and ePub formats will be available soon!

Overview

Get a head start evaluating Windows 10—with technical insights from award-winning journalist and Windows expert Ed Bott. This guide introduces new features and capabilities, providing a practical, high-level overview for IT professionals ready to begin deployment planning now.

This edition was written after the release of Windows 10 version 1511 in November 2015 and includes all of its enterprise-focused features.

The goal of this book is to help you sort out what’s new in Windows 10, with a special emphasis on features that are different from the Windows versions you and your organi­zation are using today, starting with an overview of the operating system, describing the many changes to the user experience, and diving deep into deployment and management tools where it’s necessary.

Introduction

I’ve written about Microsoft Windows for nearly a quarter-century, and in all that time I have never worked on a project like this one. Then again, I’ve never seen anything quite like Windows 10 from Microsoft, either.

With the assistance of a skilled team at Microsoft Press, I wrote this book in two phases. The first edition, published in early 2015, was based on the Windows 10 Technical Preview. For this edition, I waited until the release of Windows 10 version 1511 in November 2015 so that I could include all of its enterprise-focused features.

Windows 10 represents a major transformation of the PC landscape. For IT pros who’ve grown comfortable managing Microsoft Windows using a familiar set of tools and best practices, this version contains a startling amount of new. A new user experience. A new app platform. New security features and new management tools. New ways of deploying major upgrades.

My goal in this book is to help you sort out what’s new in Windows 10, with a special emphasis on features that are different from the Windows versions you and your organization are using today. I’ve tried to lay out those facts in as neutral a fashion as possible, starting with an overview of the operating system, describing the many changes to the user experience, and diving deep into deployment and management tools where it’s necessary.

Although I’ve written in-depth guides to Windows in the past, this book is not one of those. It’s also not a review. Only you can decide whether, and how and when, to incorporate Windows 10 into your enterprise, based on your own organizational requirements. This book is designed to serve as a starting point so that you can get more out of your evaluation of Windows 10, which is why I have also included many links to external resources.

By design, this book focuses on things that are new, with a special emphasis on topics of interest to IT pros. So you might find fewer tips and tricks about the new user experience than your users want but more about management, deployment, and security—which ultimately is what matters to the long-term well-being of the company you work for.

Windows 10 is a free upgrade for any PC running a properly licensed copy of Windows 7 or Windows 8.1 retail and OEM editions. If your organization has a Volume License for Windows Enterprise edition with Software Assurance, you also have access to Windows 10 at no cost. Even if you have no immediate plans to migrate your organization to the next version of Windows, now is the time to evaluate this new operating system.

I encourage you to share your feedback about this book directly with me. E-mail your comments to me at feedback@realworldwindows.com.

Ed Bott
January 28, 2016

Acknowledgments

I’d like to thank Michael Niehaus, Chris Hallum, and Fred Pullen, who provided invaluable input for both editions of this book. I’d also like to thank the good folks at Microsoft Press—Anne Hamilton, Rob Linsky, and Rosemary Caperton—for their efforts at making this project happen.

About the author

Ed Bott is an award-winning technology journalist and author who has been writing about Microsoft technologies for more than two decades. He is the author of more than 25 books on Microsoft Windows and Office and writes regularly about technology for The Ed Bott Report at ZDNet.

2/8 - Errata added for [MS-RDPERP]: Remote Desktop Protocol: Remote Programs Virtual Channel Extension

MSDN Blogs - Mon, 02/08/2016 - 11:12

In two sections, Section 2.2.2.4.1, Client System Parameters Update  PDU (TS_RAIL_ORDER_SYSPARAM), and Section 2.2.2.10.1, Language Profile Information  PDU (TS_RAIL_ORDER_LANGUAGEIMEINFO), corrected the field and enum names: https://msdn.microsoft.com/en-us/library/mt449537.aspx

2/8 - Errata added for [MS-RDPEMC]: Remote Desktop Protocol: Multiparty Virtual Channel Extension

MSDN Blogs - Mon, 02/08/2016 - 11:10

In Section 3.1.5.3, Processing Application, Window,  and Participant IDs, corrected the name of the ID field to Appid: https://msdn.microsoft.com/en-us/library/mt608583.aspx

2/8 - Errata added for [MS-RSMC]: Remote Session Monitoring and Control Protocol

MSDN Blogs - Mon, 02/08/2016 - 11:08

In Section 3.6.4.28.2.2, IsChatEnabledResponse, added  a description for the pfEnabled element: https://msdn.microsoft.com/en-us/library/mt449540.aspx

2/8 - Errata added for [MS-OAPX]: OAuth 2.0 Protocol Extensions

MSDN Blogs - Mon, 02/08/2016 - 11:07

Two changes: https://msdn.microsoft.com/en-us/library/mt679500.aspx

In Section 3.2.5.1.1, GET, added a domain_hint query  parameter example to the URI.

In Section 2.2.3, Common Data Structures, clarified  that the message body parameter x5c is optional.

2/8 - Errata added for [MS-ADTS]: Active Directory Technical Specification

MSDN Blogs - Mon, 02/08/2016 - 11:04

Two changes in Section 3.1.1.12.1.7, DomainDescriptionElements, to correct the element names InterDomainTrustAccounts and InterDomainTrustAccountDescription  to InterdomainTrustAccounts and InterdomainTrustAccountDescription: https://msdn.microsoft.com/en-us/library/mt226583.aspx

2/8 - Errata added for [MS-FSRVP]: File Server Remote VSS Protocol

MSDN Blogs - Mon, 02/08/2016 - 11:03

One change in Section 3.1.4.3, StartShadowCopySet (Opnum 2), to revise the processing rules: https://msdn.microsoft.com/en-us/library/mt226578.aspx

ebook deal of the week: Windows PowerShell Step by Step, Third Edition

MSDN Blogs - Mon, 02/08/2016 - 09:00

Save 50%! Buy here.

This offer expires Sunday, February 14 at 7:00 AM GMT.

This is today's definitive hands-on guide to automating Windows setup, deployment, and management with Windows PowerShell. Microsoft senior consultant Ed Wilson ("The Scripting Guy") fully illuminates every key PowerShell technique -- especially the major improvements and new cmdlets introduced with PowerShell 5.0. Wilson's positive and humorous approach has made him one of the world's most popular PowerShell instructors.

Learn more

Terms & conditions

Each week, on Sunday at 12:01 AM PST / 7:01 AM GMT, a new eBook is offered for a one-week period. Check back each week for a new deal.

The products offered as our eBook Deal of the Week are not eligible for any other discounts. The Deal of the Week promotional price cannot be combined with other offers.

The longest introduction to C#

MSDN Blogs - Mon, 02/08/2016 - 07:30

Today, I suddenly found my first book about C#. Here is the first C# program from there:

using System;
class Hello
{
public static void Main(string []args)
{
if (args.Length==0)
{
Console.WriteLine("Hello, World");
}
else
{
Console.WriteLine("Hello, " + args[0]);
}
}
}

And here is the first one that we developed with Dmitriy Nikonov in our first module about C#:

using static System.Console;

class Program
{
static void Main(string[] args)
{
WriteLine((args.Length==0) ? "Hello" : $"Hello {args[0]}");
}
}

Try to find any difference.

The first module is here.

Make Web searches safer with Bing SafeSearch

MSDN Blogs - Mon, 02/08/2016 - 06:00

February 9th is Safer Internet Day; a valuable reminder of all the ways we can help ensure kids have the safest, most secure web experience possible. And if there’s one place parents have a right to expect the highest standards, it’s at school.

...(read more)

Make Web searches safer with Bing SafeSearch

MSDN Blogs - Mon, 02/08/2016 - 06:00

February 9th is Safer Internet Day; a valuable reminder of all the ways we can help ensure kids have the safest, most secure web experience possible. And if there’s one place parents have a right to expect the highest standards, it’s at school.

...(read more)

【2/25(木) 21:00 - 22:00 スクー生放送】 Visual Studio アプリ開発超入門 ~ 第2回 : Visual Studio Code と HTML5 でシンプルなゲームを作ろう

MSDN Blogs - Mon, 02/08/2016 - 04:03
スクーで大好評のVisual Studio Codeの2回目の授業です。今回からいよいよハンズオン形式で実際にゲームを開発します。Visual Studio Codeの使い方がわかる初心者におすすめの授業です。ぜひご覧ください。 ■日時 第2回:2/25(木)21:00 - 22:00 ■講師 井上 章(日本マイクロソフト株式会社 エバンジェリスト) ■授業内容 Mac OS XでもLinuxでもWindowsでも無償で使える高機能エディター Visual Studio Code を使ったWebアプリケーション開発入門の3回シリーズです。 第2回目は、Webブラウザで動作するHTML5とJavaScriptを使った簡単なゲームアプリを作ります。授業を通して、Visual Studio Code を使ったHTMLやJavaScriptのコーディング方法や、HTML5のCanvasを使った画像の表示方法などを学習します。 ※授業はハンズオン形式で体験しながら進めます。 ※前回の授業 ( https://schoo.jp/class...(read more)

You receive “Installation cannot be performed” when trying to install Microsoft BizTalk 2013 R2 Accelerator for HL7

MSDN Blogs - Mon, 02/08/2016 - 03:32

Symptom

You get the following error message when trying to install Microsoft BizTalk 2013 R2 Accelerator for HL7:

“Error: Installation cannot be performed because the BizTalk server has not been configured or user account is not a member of the BizTalk Server Administrators group.”

 

Possible causes

1.     Confirm that user executing Microsoft BizTalk 2013 R2 Accelerator for HL7 is part of the BizTalk Server Administrator Group.

2.     If installing HL7 in a distributed environment, computer and logged user  (the one executing HL7 wizard) must have access to Primary Domain Controller (PDC).  If it fails to access PDC, it will fail early on in the installation and it won’t allow you to continue. 

3.     BizTalk Server should have a default 32bit BizTalk Host ‘BizTalkServerApplication’.

4.     Confirm that SQL client tools is installed on BizTalk servers.

 

Hope it helps!!

 

Вышла новая версия Visual Studio Tools for Unity

MSDN Blogs - Mon, 02/08/2016 - 03:30

Несколько дней назад случился важный релиз для всех Unity-разработчиков, которые привыкли использовать удобный софт для разработки под Unity: вышла новая версия Visual Studio Tools for Unity. На этот раз 2.2.

Ликбез для тех, кто Студию почему-то не использует: c версии 2.1 VSTU имеют нативную поддержку Unity и, соответственно, возможность максимально интегрировать Visual Studio в свою безбедную жизнь отечественного игрового разработчика.





Основные изменения:
1) Установщик VSTU максимально корректно доставляет всю информацию, необходимую Unity в процессе интеграции;
2) Корректная отладка Unity-игр под OS X и в виртуальных машинах;
3) В Unity 4.6 VSTU корректно расставляет референсы на UnityEngine и UnityEditor;
4) Поддерживается только C# 4 (как и непосредственно в Unity);
5) Исправлена ошибка в Unity package, которая могла проявляться в проектах вообще без скриптов.

Для тех, кто пишет сетевые игры и использует NetworkBehaviour, в VSTU 2.2 добавлена поддержка сетевых сообщений (см. скриншот ниже)



Так как VSTU нативно поддерживаются в Unity, достаточно просто установить их из Visual Studio Gallery и назначить Visual Studio редактором по умолчанию на вкладке External Tools в Unity Preferences. Подробно о настройке можно прочитать на сайте разработчиков.



После этого поддержка VSTU будет включена автоматически. Можно очень легко в этом убедиться в нижней части окна About Unity.



Важный момент: для версии Unity 5.1 и ниже вам придется переимпортировать пакет VSTU в свой проект, и решение Visual Studio будет создано с префиксом UnityVS. Для всех свежих версий Unity (начиная с 5.2) в этом нет необходимости, но если вы использовали VSTU со старшей версией Unity, то потребуется удалить папку UnityVS из проекта.

С полным списком изменений можно ознакомиться на MSDN , а ссылки на скачивание VSTU для разных версий Visual Studio находятся буквально в следующей строке:
Visual Studio 2015 Tools for Unity
Visual Studio 2013 Tools for Unity
Visual Studio 2012 Tools for Unity
Visual Studio 2010 Tools for Unity

На этом новость закончилась. Надеемся, что эта она принесла немного позитива в этот хмурый понедельник и вам (нам принесла).
Продуктивной недели и оставайтесь с нами!

Script to run MAPI executable at logon via GPO

MSDN Blogs - Mon, 02/08/2016 - 01:20

 

The script below allows you to run a MAPI executable at logon via GPO. It detects the office version and bitness and it runs the exe version matching the bitness of Outlook.

The syntax to use is the following:

RunExe.vbs ROOT_FOLDER  EXE_NAME  PARAMETERS  RUN_OPTION_RERUN

For example, presuming I’ve stored the 32 bit version of an executable in \\CONDC-01\Netlogon\Myexe\x86 and the 64 bit version in \\CONDC-01\Netlogon\Myexe\x64 and the executable name is myexe.exe, to run the executable once and prevent future executions you would use the following syntax:

RunExe.vbs “\\CONDC-01\Netlogon\Myexe” “Myexe.exe” “param1 param2 param3” false

If your parameters contain quotes, please replace them with apostrophes “’”. For example instead of “param1 “C:\Temp”” use “param1 ‘C:\temp”"’”

Dim checkpoint, OfficeVersion, OfficeBitness, ServerSIPUri, PublicMeeting, strDirectory, objFSO, objFSOText, objFolder, objFile, strBitness
strDirectory = WScript.Arguments(0)
strExeName = WScript.Arguments(1)
strArguments = Replace(WScript.Arguments(2),Chr(39), Chr(34))
boolRerun = CBool(WScript.Arguments(3))
Const HKEY_CLASSES_ROOT    = &H80000000
Const HKEY_CURRENT_USER    = &H80000001
Const HKEY_LOCAL_MACHINE   = &H80000002

Function GetOfficeVersion
    strTempKeyPath = "Outlook.Application\CurVer"
    strTempValueName = ""
    oReg.GetStringValue HKEY_CLASSES_ROOT, strTempKeyPath, strTempValueName, strValue
    If (Not IsNull(strValue)) Then
        Select Case strValue
               Case "Outlook.Application.16"
                   GetOfficeVersion = "16.0"
            Case "Outlook.Application.15"
                      GetOfficeVersion = "15.0"
               Case "Outlook.Application.14"
                   GetOfficeVersion = "14.0"                                                       
        End Select
    End If
End Function

Function GetOutlookBitness
    strTempKeyPath = "SOFTWARE\Microsoft\Office\" & GetOfficeVersion & "\Outlook"
    strTempValueName = "Bitness"
    oReg.GetStringValue HKEY_LOCAL_MACHINE, strTempKeyPath, strTempValueName, strValue
    If (Not IsNull(strValue)) Then
        GetOutlookBitness = strValue
    End If
End Function

Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
If (Not boolRerun) then
    strKeyPath = "SOFTWARE\Microsoft\Office\" & GetOfficeVersion & "\Outlook"
    strValueName = "checkpoint"
    oReg.GetDWORDValue HKEY_CURRENT_USER, strKeyPath, strValueName, strValue
End if
If ((IsNull(strValue)) or (strValue = 0)) Then
    strBitness = GetOutlookBitness
    cmd = strDirectory & "\" & strBitness & "\" & strExeName & " " & strArguments
    Set oShell = CreateObject("WScript.Shell")
    oShell.Run cmd
    If (Not boolRerun) then
        oReg.SetDWORDValue HKEY_CURRENT_USER, strKeyPath, strValueName, 1
    End if
End If   
Set oReg = Nothing

Office 365 in Education Event Hosted by Microsoft and Coretek

MSDN Blogs - Mon, 02/08/2016 - 01:15

 

On Tuesday 23rd February, Microsoft will be hosting an Office 365 in Education event for students and teachers in partnership with Coretek. This guest blog comes from our education partner Coretek outlining what you can expect from the Office 365 in Education Event.

Click here to register

Educational technology experts Microsoft and Coretek are proud to present this unique one-off event on Office 365 for schools. Get expert advice on the latest Office tips and tricks from the very company that brought you the Office suite.

Learn how to empower staff with new levels of efficiency and access your files from anywhere with OneDrive. Pupils can collaborate and work together in new ways using OneNote. Plus much more!

In addition to this, every school that attends will be shown through the whole Office 365 sign-up process. By the end of the day every pupil that is invited, will learn to set up their own Office 365 account and access their 5 free copies of Microsoft Office. These pupils will then have the knowledge to become “Office 365 Evangelists” and teach their fellow pupils how to create their own accounts and make the most out of Office 365.

The event will be hosted are Microsoft’s UK Headquarters, at Thames Valley Park campus in Reading. This is an unmissable opportunity to gain access to one of the biggest technology companies in the world.

This is an event that any school using Microsoft Office will not want to miss!

Event details:

Date: Tuesday 23rd February 2016

Time: 10am - 3:30pm

Venue: Microsoft HQ, Thames Valley Park, Reading, RG6 1WG

Register and find out more here

Guest post: Comunicare con una socket in una Universal Windows app

MSDN Blogs - Mon, 02/08/2016 - 01:13

Questo post è stato scritto da Matteo Pagani, Windows AppConsult Engineer in Microsoft

Le socket sono uno dei meccanismi di comunicazione più diffusi quando si ha la necessità di far parlare tra di loro due applicazioni all'interno della stessa rete. Le socket vengono spesso usate in contesti in cui non è disponibile un accesso ad Internet oppure è necessario scambiare pacchetti e informazioni in formati personalizzati: è possibile sfruttare, infatti, lo stesso protocollo utilizzato nel mondo web (TCP) ma senza dover necessariamente comunicare tramite uno dei protocolli standard come HTTP, FTP, ecc.

Una socket è fondamentalmente un canale che coinvolge due attori: un server, che si fa carico di creare il canale, e un client, che invece si collega al canale. Una volta stabilita la comunicazione, entrambi possono scambiarsi pacchetti contenenti dati di qualsiasi tipo: messaggi di testo, file binari, immagini, ecc. Al giorno d'oggi, le socket sono sicuramente meno diffuse che in passato, soprattutto in ambito mobile: dato che parliamo di dispositivi che vivono sempre connessi ad Internet, per la maggior parte dei casi si preferisce affidarsi ai meccanismi di comunicazione consentiti dal protocollo HTTP e dai vari comandi POST, GET, ecc.

Esistono però ancora alcuni scenari per cui la connessione tramite socket ha grande importanza:

  1. La comunicazione diretta tra due dispositivi collegati in rete: per diversi scenari (ad esempio, la comunicazione tra due pc o tra un dispositivo mobile ed un pc) l'utilizzo di Internet non è necessario, anzi, aggiungerebbe un overhead inutile perché sarebbe un terzo attore che dovrebbe fare da tramite nella comunicazione. Ad esempio, ipotizziamo di avere un'applicazione mobile che permetta di controllare in remoto un computer collegato alla stessa rete: in tal caso, l'utilizzo di Internet come canale di comunicazione potrebbe essere un requisito di troppo, perché non è detto che entrambi i dispositivi abbiano connettività in quel momento.
  2. La mancanza di connettività ad Internet: si tratta di uno scenario piuttosto frequente in scenari enterprise, in cui si hanno in dotazione dispositivi che, per motivi di sicurezza, non sono collegati ad Internet ma comunicano con un server solamente tramite reti private. Pensiamo ad esempio ad un'applicazione di messaggistica (stile WhatsApp) interna, che consenta di scambiare messaggi tra i vari dispositivi aziendali, anche senza la presenza di una connessione ad Internet.

Nel corso di questo post andremo a vedere come collegarci ad una socket in un'applicazione per Windows 10. La maggior parte delle API che andremo ad utilizzare, in realtà, erano disponibili già in 8.1; la novità principale di 10 è la possibilità di avere un background task legato ad una socket, in modo da poter ricevere messaggi anche quando questa non è in esecuzione.

Il progetto

Nel corso di questo post realizzeremo un progetto composto da tre attori:

  1. Un'applicazione server, che si farà carico di creare la socket e inviare messaggi verso il client. Nel nostro caso vogliamo simulare una socket "reale" (quindi indipendente dalla Universal Windows Platform di Windows 10): il server sarà perciò realizzato con un'applicazione WPF, sfruttando le API del framework .NET che avremmo potuto utilizzare anche in una soluzione web. A dimostrazione di questa "indipendenza", alla fine del post troverete anche un breve esempio su come realizzare il server sfruttando Node.js, una tecnologia completamente slegata dal mondo Microsoft e .NET.
  2. Un'applicazione client, che si farà carico di collegarsi alla socket e scambiare messaggi con il server. È il contesto in cui ci interessa mettere alla prova la Universal Windows Platform e sarà sviluppata, perciò, come Universal Windows app per Windows 10.
  3. Un background task, che sarà collegato all'applicazione client e che utilizzeremo per ricevere i messaggi spediti dal server anche quando l'applicazione non è in esecuzione.

Quella che andremo a realizzare è la simulazione di un'applicazione di messaggistica: quando il client Windows 10 riceverà un messaggio dal server mentre è in esecuzione lo mostrerà semplicemente nell'app stessa. Quando, invece, l'app non è in esecuzione, il messaggio sarà intercettato dal background task e lo mostrerà sotto forma di notifica toast all'utente.

Iniziamo, c'è parecchio lavoro da fare

L'applicazione server

Come anticipato, andremo a simulare il server con un'applicazione desktop sviluppata in WPF. Possiamo creare un nuovo progetto di questo tipo in Visual Studio, scegliendo la categoria Classic Desktop e, infine, la voce WPF Application. WPF, esattamente come la Universal Windows Platform, sfrutta lo XAML come tecnologia per definire il layout di un'applicazione. Il nostro layout sarà molto semplice:

  1. Un pulsante, che si occuperà di creare la socket.
  2. Un casella di testo, dove inserire il messaggio che vogliamo inviare sul canale.
  3. Un altro pulsante, che invierà il messaggio al client.

<Window x:Class="SocketServer.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

mc:Ignorable="d"

Title="MainWindow" Height="350" Width="525">

 

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">

<TextBlock Text="Socket Server" FontSize="24" HorizontalAlignment="Center" />

<Button Content="Create socket" Click="OnCreateSocketClicked" Width="200" Margin="0, 20, 0, 0" />

<TextBlock Text="Enter a message:" Margin="0, 20, 0, 0" />

 

<StackPanel Orientation="Horizontal" >

<TextBox x:Name="Message" Width="300" />

<Button Content="Send text" Click="OnSendTextClicked" />

</StackPanel>

</StackPanel>

</Window>

 

Come vedete, il codice XAML è piuttosto semplice da interpretare. Andiamo subito perciò al sodo e vediamo come poter creare una socket utilizzando le API offerte dal framework .NET. Ecco come appare il metodo di creazione della socket:

private void OnCreateSocketClicked(object sender, RoutedEventArgs e)

{

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

IPAddress ipAddress = IPAddress.Loopback;

IPEndPoint endPoint = new IPEndPoint(ipAddress, 1983);

socket.Bind(endPoint);

socket.Listen(10);

socket.BeginAccept(AcceptCallback, socket);

}

Il punto di partenza è la classe Socket, appartenente al namespace System.Net.Sockets, che richiede nel costruttore una serie di parametri di configurazione. In questo esempio, andremo a creare una socket basata sul protocollo TCP, in grado di comunicare tra i dispositivi sfruttando gli indirizzi IP delle rispettive schede di rete. Per questo motivo, specifichiamo:

  1. Come primo parametro, AddressFamiliy.InterNetwork, per specificare che vogliamo utilizzare il protocollo IPv4 per la comunicazione. L'enumeratore può assumere molti altri valori, legati ad altre tipologie di protocollo (AppleTalk, IPv6, ecc.)
  2. Come secondo parametro, la tipologia di socket con cui vogliamo lavorare. In questo caso, decidiamo di scambiare i dati sul canale sfruttando degli stream di dati, tramite il valore SocketType.Stream.
  3. Come terzo parametro, il protocollo da utilizzare. Come già anticipato, vogliamo utilizzare il protocollo TCP, passiamo perciò il valore ProtocolType.Tcp. Un altro protocollo piuttosto diffuso per le socket è UDP, più veloce ma meno affidabile, in quanto non si ha la garanzia che ogni pacchetto venga consegnato con successo o nello stesso esatto ordine in cui lo abbiamo inviato, al contrario di TCP.

Una socket è legata a doppio filo ad un endpoint, ovvero il punto di accesso a cui i client si collegheranno per stabilire la comunicazione. Nel nostro caso (ovvero una socket basata sul protocollo TCP/IP), l'endpoint è costituito da un indirizzo IP e da una porta. Per il nostro esempio, sfrutteremo l'indirizzo locale della macchina (il canonico localhost), tramite il valore Loopback della classe IPAddress. Con un oggetto di tipo IPAddress siamo in grado di creare un'istanza di un IPEndPoint, a cui dobbiamo passare anche il numero di porta che vogliamo utilizzare. Nel nostro esempio, abbiamo creato una socket che risponderà all'indirizzo localhost:1983.

Ora che abbiamo definito l'endpoint, possiamo aprire il canale di comunicazione vera e proprio: lo facciamo chiamando il metodo Bind() e, successivamente, Listen(), specificando il numero di connessione contemporanee che vogliamo poter accettare.

Da questo momento in poi il canale è stato creato: ora dobbiamo prepararci a ricevere le connessioni in ingresso dai client. Lo facciamo sfruttando i metodi asincroni offerti dal framework .NET, che però utilizzano un approccio diverso da quello basato su async e await che siamo abituati ad utilizzare nelle Universal Windows app. Questo perché la comunicazione con le socket è asincrona non solo in quanto non vogliamo bloccare il thread della UI mentre il canale è aperto, ma anche e soprattutto perchè non sappiamo quando avverrà tale comunicazione: il client potrebbe collegarsi al server dopo 1 secondo, 10 minuti od un'ora che il canale è stato creato.

Ecco qual è lo scopo del metodo BeginAccept(): il canale rimarrà in ascolto di connessioni da parte dei client e, appena ne intercetterà una in arrivo, eseguirà il metodo di callback che abbiamo passato come primo parametro (nel nostro caso, si chiama AcceptCallback). Il secondo parametro è un semplice riferimento all'oggetto stesso di tipo Socket con cui abbiamo creato il canale.

Ecco come appare la definizione del metodo AcceptCallback.

private void AcceptCallback(IAsyncResult ar)

{

Socket socketChannel = socket.EndAccept(ar);

}

Quello che vedete è un classico esempio di gestione di operazioni asincrone sfruttando le callback e i prefissi Begin() e End(). Tale approccio prevede la presenza di un metodo preceduto dal prefisso Begin (nel nostro caso, BeginAccept()) che dà avvio all'operazione. Nel momento in cui questa è terminata e siamo pronti per elaborare i risultati, viene invocato il metodo di callback, all'interno del quale possiamo chiamare il metodo preceduto dal prefisso End (nel nostro caso, EndAccept), passando come parametro il risultato di tipo IAsyncResult che fa parte dei parametri della callback. La chiamata a tale metodo ci restituisce il risultato vero e proprio dell'elaborazione, che nel nostro caso è un altro oggetto di tipo Socket, questa volta però collegato al canale di comunicazione attivo e aperto verso il client. Nell'applicazione WPF di esempio, tale canale sarà memorizzato in una variabile globale della pagina: ci servirà successivamente, infatti, quando vorremo inviare dei dati.

Come inviamo dei dati sul canale? In realtà, le socket non hanno il concetto di "tipo di dati": sono semplicemente dei bocchettoni, in cui far transitare dei pacchetti, che poi il ricevente si farà carico di interpretare. Ecco perciò che se, per il nostro scenario, vogliamo inviare dei messaggi testuali, dobbiamo prima convertirli in un array di byte, come nell'esempio seguente:

private void OnSendTextClicked(object sender, RoutedEventArgs e)

{

if (socketChannel != null)

{

string message = Message.Text;

byte[] bytes = Encoding.ASCII.GetBytes(message);

socketChannel.Send(bytes);

}

}

Questo è il metodo collegato alla pressione del pulsante nello XAML di invio di un messaggio: si fa carico di recuperare il testo inserito dall'utente, di convertirlo in un array di byte tramite il metodo GetBytes() della classe statica Encoding.ASCII e di inviarlo sfruttando il metodo Send() della classe Socket. Come potete notare, per l'invio sfruttiamo il riferimento alla socket che abbiamo ottenuto nella callback AcceptCallback(). In questo modo, siamo sicuri di inviare il messaggio verso un canale attivo a cui è collegato un client.

L'applicazione server, per il momento, è terminata: possiamo lanciarla e premere il pulsante Create socket per creare il nostro canale di comunicazione. Potremmo anche provare ad inviare dei messaggi ma, ovviamente, non succederà nulla dato che, al momento, non c'è alcun client collegato.

L'applicazione client

L'applicazione client, che si collegherà alla socket appena creata, sarà una vera e propria Universal Windows app per Windows 10, in grado di funzionare, perciò, su molteplici dispositivi (pc, tablet, telefoni, ecc.). La differenza principale tra un'applicazione WPF e una Universal Windows app è la tecnologia su cui sono basate: da una parte il framework .NET tradizionale, dall'altra la nuova Universal Windows Platform, costruita come evoluzione del Windows Runtime introdotto in Windows 8. Come conseguenza, per l'applicazione client dovremo utilizzare delle API differenti da quelle che abbiamo visto per l'applicazione server: nella Universal Windows Platform, infatti, non troviamo il namespace System.Net.Sockets e classi come Socket, IPEndPoint, ecc, ma un nuovo set di API incluso nel namespace Windows.Networking.Sockets.

Per iniziare dobbiamo perciò creare un nuovo progetto di tipo Windows Universal.

Iniziamo a vedere come utilizzarle per collegarci alla nostra socket. L'operazione base è molto semplice:

private async void OnForegroundSocketClicked(object sender, RoutedEventArgs e)

{

StreamSocket socket = new StreamSocket();

HostName host = new HostName("localhost");

 

try

{

await socket.ConnectAsync(host, "1983");

 

}

catch (Exception exc)

{

MessageDialog dialog = new MessageDialog("Error connecting to the socket");

await dialog.ShowAsync();

}

}

L'oggetto che rappresenta il nostro canale è di tipo StreamSocket ed espone i vari metodi per interagire con la socket. Per collegarsi al canale è necessario utilizzare il metodo ConnectAsync() che richiede, come parametri, un oggetto di tipo HostName con l'indirizzo del canale (nel nostro caso, localhost, dato che la socket gira in locale) e la porta (nel nostro caso, 1983). A questo punto, se tutto è andato a buon fine, la connessione è attiva e possiamo iniziare a metterci in ascolto di messaggi in arrivo dal server. Come citato in precedenza, però, la socket è fondamentalmente un bocchettone sempre aperto, nel quale i dati possono arrivare in qualsiasi momento. Dobbiamo, perciò, adottare lo stesso approccio per la ricezione: dobbiamo mantenere il canale di lettura sempre attivo e risvegliarlo solo nel momento in cui arrivano effettivamente dei dati.

Ecco come appare l'operazione completa di connessione:

private async void OnForegroundSocketClicked(object sender, RoutedEventArgs e)

{

socket = new StreamSocket();

HostName host = new HostName("localhost");

 

try

{

await socket.ConnectAsync(host, "1983");

 

isConnected = true;

while (isConnected)

{

try

{

DataReader reader;

 

using (reader = new DataReader(socket.InputStream))

{

// Set the DataReader to only wait for available data (so that we don't have to know the data size)

reader.InputStreamOptions = InputStreamOptions.Partial;

// The encoding and byte order need to match the settings of the writer we previously used.

reader.UnicodeEncoding = UnicodeEncoding.Utf8;

reader.ByteOrder = ByteOrder.LittleEndian;

 

// Send the contents of the writer to the backing stream.

// Get the size of the buffer that has not been read.

await reader.LoadAsync(256);

 

// Keep reading until we consume the complete stream.

while (reader.UnconsumedBufferLength > 0)

{

string readString = reader.ReadString(reader.UnconsumedBufferLength);

await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>

{

messages.Add(readString);

});

Debug.WriteLine(readString);

await reader.LoadAsync(256);

}

 

reader.DetachStream();

 

}

 

}

catch (Exception exc)

{

MessageDialog dialog = new MessageDialog("Error reading the data");

await dialog.ShowAsync();

}

}

}

catch (Exception exc)

{

MessageDialog dialog = new MessageDialog("Error connecting to the socket");

await dialog.ShowAsync();

}

}

La lettura dei dati viene inclusa all'interno di un ciclo while, in cui viene valutato il valore di una variabile booleana: fintanto che questa è a true, il "bocchettone" rimane aperto. Nello specifico, dato che si tratta di un'operazione di lettura, il bocchettone è rappresentato dalla proprietà InputStream dell'oggetto StreamSocket: è al suo interno che troveremo i dati spediti dal server. La lettura viene effettuata utilizzando le API del Windows Runtime dedicate alla manipolazione di stream di dati: se avete esperienza con la scrittura e la lettura di stream di file all'interno dello storage locale, noterete che il codice è molto simile.

Il cuore è la classe DataReader, che permette di leggere i dati contenuti all'interno di uno stream, nel nostro caso l'InputStream della socket. Dopodichè, prima di iniziare la lettura vera e propria, dobbiamo configurare in maniera opportuna l'oggetto DataReader: nello specifico, la proprietà più importante è InputStreamOptions, che deve essere impostata su Partial. Questo perché, trattandosi di un canale sempre aperto, non possiamo sapere a priori quanto sarà grande il dato che ci arriverà: questa opzione ci permette di leggere stream anche parziali, senza dover specificare necessariamente la dimensione totale. Per lo stesso motivo, quando iniziamo l'operazione di lettura vera e propria ci viene in aiuto la proprietà UnconsumedBufferLength del DataReader per sapere se, all'interno dello stream, ci sono dei dati ancora non letti: andremo a leggere il dato solo se, effettivamente, la dimensione del buffer è maggiore di 0.

Uno dei punti di forza della classe DataReader è che espone diversi metodi che semplificano la lettura dello stream, dandoci la possibilità di ottenere direttamente il tipo di dato atteso. Nel nostro caso, dato che l'applicazione server aveva inviato un messaggio testuale, lo possiamo leggere grazie al metodo ReadString(), che si farà carico in automatico di convertire i byte in stringa. Finalmente abbiamo recuperato il messaggio inviato dal server: sta a noi, in base alla logica della nostra applicazione, farne buon uso. Nell'esempio di codice la stringa viene aggiunta ad una collezione di tipo ObservableCollection<string>, che è collegata ad un controllo ListView presente nella pagina XAML: in questo modo, ogni volta che l'applicazione WPF invierà un messaggio, lo vedremo comparire all'interno della pagina della nostra applicazione Windows 10.

E se volessimo terminare la connessione alla socket e chiudere il canale? È sufficiente demandare, ad un altro pulsante, la valorizzazione della proprietà boolana isConnected to false: in questo modo, si interromperà il ciclo while definito in precedenza e la classe DataReader smetterà di attendere l'arrivo di nuovi dati. Se vogliamo chiudere completamente la connessione, possiamo anche invocare il metodo CancelIOAsync() (per cancellare eventuali operazioni in corso) e poi chiamare il Dispose() sull'oggetto StreamSocket. Ecco un esempio completo:

private async void OnCloseConnectionClicked(object sender, RoutedEventArgs e)

{

isConnected = false;

await socket.CancelIOAsync();

socket.Dispose();

}

Ricevere i messaggi in background

Ora che abbiamo visto la ricezione dati in foreground (ovvero mentre l'applicazione è in esecuzione), introduciamo un nuovo scenario supportato specificatamente da Windows 10: la ricezione di messaggi in background, ovvero anche quando l'applicazione non è in esecuzione. Per farlo dobbiamo utilizzare il meccanismo dei background task, che dovremmo conoscere già se abbiamo esperienza di sviluppo applicazioni Windows: si tratta di progetti di tipo Windows Runtime Component, separati dall'applicazione vera e propria ma appartenenti alla stessa soluzione di Visual Studio, che contengono il codice che vogliamo eseguire quando il task viene avviato. Potete approfondire l'argomento grazie alla documentazione ufficiale all'indirizzo https://msdn.microsoft.com/en-us/library/windows/apps/mt299103.aspx. I task sono legati ai trigger, ovvero gli eventi che possono scatenarne l'esecuzione anche quando l'applicazione principale non è in uso da parte dell'utente. Windows 10 ha introdotto un nuovo trigger chiamato SocketActivityTrigger, che permette di trasferire la connessione ad una socket dall'applicazione in foreground al task in background: ogni volta sarà rilevata la presenza di un nuovo messaggio nel canale, il task si risveglierà e potrà riceverlo ed elaborarlo.

Il primo passo è quello di creare il background task vero e proprio: creiamo, nella nostra soluzione, un nuovo progetto di tipo Windows Runtime Component e, al suo interno, creiamo una nuova classe, a cui possiamo dare un nome a piacimento. E' fondamentale, però, che questa erediti dall'interfaccia IBackgroundTask: ciò ci costringerà ad implementare il metodo Run(), che è quello che viene invocato quando il task viene eseguito. All'interno di tale metodo potremo capire per quale motivo la socket è stata attivata e, in base allo scenario, leggere il dato ricevuto sul canale. Ecco come appare la definizione del nostro task:

namespace SocketTask

{

public sealed class ReceiveMessagesTask: IBackgroundTask

{

public async void Run(IBackgroundTaskInstance taskInstance)

{

var deferral = taskInstance.GetDeferral();

var details = taskInstance.TriggerDetails as SocketActivityTriggerDetails;

var socketInformation = details.SocketInformation;

 

if (details.Reason == SocketActivityTriggerReason.SocketActivity)

{

StreamSocket 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);

}

 

deferral.Complete();

}

 

 

public void ShowToast(string text)

{

string xml =

$@"

<toast activationType='foreground' launch='args'>

<visual>

<binding template='ToastGeneric'>

<text>Message from the socket</text>

<text>{text}</text>

</binding>

</visual>

</toast>";

 

XmlDocument doc = new XmlDocument();

doc.LoadXml(xml);

 

ToastNotification notification = new ToastNotification(doc);

ToastNotifier notifier = ToastNotificationManager.CreateToastNotifier();

notifier.Show(notification);

}

}

}

 

Il metodo Run() contiene un parametro di tipo IBackgroundTaskInstance, che include le principali informazioni sul task. Nello specifico, espone una proprietà di nome TriggerDetails, che viene valorizzata di volta in volta con un oggetto specifico in base al tipo di trigger a cui è collegato il task. Nel nostro caso, dato che stiamo gestendo un trigger di tipo SocketActivityTrigger, tale oggetto sarà di tipo SocketActivityTriggerDetails e ci permetterà di accedere alla socket vera e propria. Sono due le informazioni essenziali che ci servono:

  1. La proprietà SocketInformation , checontiene un riferimento alla socket e include l'oggetto di tipo StreamSocket che ci serve per leggere e scrivere dati.
  2. La proprietà Reason, che contiene l'informazione su quale evento legato alla socket ha scatenato l'attivazione del task. Nel nostro caso, ci limitiamo a gestire il valore SocketActivity dell'enumeratore SocketActivityTriggerReason: significa che sono arrivati dei dati sul canale, che possiamo leggere. Altri valori possibili sono ConnectionAccepted (quando il client si è collegato con successo al server), SocketClosed (quando il canale di comunicazione è stato chiuso), ecc.

A questo punto il codice che andiamo a scrivere è molto simile a quello che abbiamo visto nell'applicazione vera e propria: usando la classe DataReader andiamo a leggere il contenuto dell'InputStream e lo convertiamo in stringa tramite il metodo ReadString(). Dato che ci troviamo in un task in background, non abbiamo accesso diretto al thread della UI, perchè l'applicazione potrebbe non essere in esecuzione. Se vogliamo interagire con l'utente dobbiamo, perciò, usare altri meccanismi, come l'uso di notifiche: è quello che facciamo con il metodo ShowToast(), che mostra il contenuto del messaggio sotto forma di notifica toast., usando il meccanismo di Windows 10 delle Adaptive Toast (che possiamo approfondire all'indirizzo http://blogs.msdn.com/b/tiles_and_toasts/archive/2015/07/02/adaptive-and-interactive-toast-notifications-for-windows-10.aspx). Una volta terminata l'operazione di lettura, restituiamo il controllo della socket al sistema operativo tramite il metodo TransferOnwership(): Windows 10 include, infatti, un servizio che si fa carico di tenere sotto controllo la socket e di attivare il task nel momento in cui si è verificata qualche attività.

Ora che il background task è pronto, dobbiamo opportunamente registrarlo nell'applicazione principale. La procedura è quella standard per i background task:

  1. Si aggiunge, nella sezione Declarations del file di manifest, un oggetto di tipo Background Tasks, specificando:
    1. Come Supported task types, la voce System event.
    2. Nella casella Entry point, occorre specificare la firma completa della classe che implementa l'interfaccia IBackgroundTask, composta da namespace più il nome della classe. Nell'esempio precedente, è SocketTask.ReceiveMessageTask.

  1. Si registra il task all'avvio dell'applicazione, tramite la classe BackgroundTaskBuilder, come nell'esempio seguente:

protected override async void OnNavigatedTo(NavigationEventArgs e)

{

var registration = BackgroundTaskRegistration.AllTasks.FirstOrDefault(x => x.Value.Name == TaskName);

if (registration.Value == null)

{

var socketTaskBuilder = new BackgroundTaskBuilder();

socketTaskBuilder.Name = TaskName;

socketTaskBuilder.TaskEntryPoint = "SocketTask.ReceiveMessagesTask";

var trigger = new SocketActivityTrigger();

socketTaskBuilder.SetTrigger(trigger);

var status = await BackgroundExecutionManager.RequestAccessAsync();

if (status != BackgroundAccessStatus.Denied)

{

task = socketTaskBuilder.Register();

}

}

else

{

task = registration.Value;

}

}

Innanzitutto si verifica che non esista già un background task registrato con lo stesso nome, per evitare registrazioni multiple dello stesso task. Solo in caso non esista già, procediamo a registrarlo specificandone un nome univoco (la proprietà Name) e l'entry point (la proprietà TaskEntryPoint, occorre valorizzarla con lo stesso dato inserito nel file di manifest, ovvero la firma completa della classe che implementa il task). Con il metodo SetTrigger() configuriamo quale trigger vogliamo associare a questo task: nel nostro caso, si tratta di un SocketActivityTrigger. Infine verifichiamo tramite il metodo RequestAccessAsync() se siamo autorizzati a registrare il task (su un dispositivo con poca memoria, infatti, potrebbe essere già stato raggiunto il numero massimo di task registrabili) e, in caso affermativo, chiamiamo il metodo Register(). Possiamo notare come manteniamo, a livello di pagina, un riferimento al task registrato: questo perché ci servirà l'identificativo assegnato dal sistema operativo nel momento in cui dovremo registrare la socket. L'ultimo passaggio è aggiungere, all'applicazione, un riferimento al Windows Runtime Component che contiene il task: facciamo clic con il tasto destro in Visual Studio sul progetto dell'applicazione, scegliamo Add reference e, alla voce Projects, andiamo a scegliere il Windows Runtime Component.

Ora che il background task è stato registrato correttamente, possiamo procedere a collegarci alla socket e a trasferire il controllo al sistema operativo: non sarà più, infatti, la nostra applicazione a rimanere in ascolto di eventuali comunicazioni in arrivo sul canale, ma lo farà Windows per noi, il quale attiverà il nostro task se necessario. Ecco il codice da eseguire:

private async void OnBackgroundSocketClicked(object sender, RoutedEventArgs e)

{

StreamSocket socket = new StreamSocket();

HostName host = new HostName("localhost");

 

await socket.ConnectAsync(host, "1983");

socket.EnableTransferOwnership(task.TaskId, SocketActivityConnectedStandbyAction.Wake);

socket.TransferOwnership("SampleSocket");

}

La prima parte è la medesima vista in precedenza: creiamo un nuovo oggetto di tipo StreamSocket e ci colleghiamo al canale legato all'indirizzo localhost e alla porta 1983. Dopodichè abilitiamo il trasferimento del controllo al sistema tramite il metodo EnableTransferOwnership(): il primo parametro da passare è l'identificativo del background task che abbiamo registrato, da cui la necessità di memorizzare il risultato dell'operazione Register() in una variabile globale. L'identificativo è memorizzato all'interno della proprietà TaskId. Il secondo parametro è legato, invece, al concetto di Connected Standby, ovvero quando il device si trova in uno stato di "non utilizzo" (ad esempio, telefono bloccato in tasca o PC in stand-by): tramite questo parametro possiamo specificare se vogliamo che il sistema operativo attivi il task anche in questo scenario, tramite uno dei valori dell'enumeratore SocketActivityConnectedStandbyAction. Nel nostro caso, vogliamo che il sistema operativo sia in grado di intercettare dati dalla socket in qualsiasi momento, perché l'utente potrebbe ricevere un messaggio anche quando non sta attivamente usando il telefono: sfruttiamo, perciò, il valore Wake.

Infine, trasferiamo il controllo della socket al sistema operativo tramite il metodo TransferOnwnership(), passando come parametro una stringa che identifica in maniera univoca la socket. Il gioco è fatto: se ora sospendessimo l'app e provassimo ad inviare un messaggio dall'applicazione WPF, lo vedremo arrivare sotto forma di notifica toast, in quanto sarà intercettato dal background task. Il task è una classe a tutti gli effetti, che possiamo debuggare esattamente come l'applicazione vera e propria: se vogliamo vedere cosa sta succedendo in dettaglio, non dobbiamo far altro che mantenere il debugger di Visual Studio collegato e mettere dei breakpoint all'interno del metodo Run().

E se volessimo rispondere al messaggio?

Nel nostro esempio abbiamo identificato un server (l'applicazione WPF) e un client (l'applicazione Windows 10), ma questo non significa che solo la prima sia in grado di inviare messaggi verso la seconda. Anche il client, a sua volta, può inviare dei dati sul canale, che saranno ricevuti dal server. Dal punto di vista dell'applicazione Windows 10, come possiamo vedere si tratta di un'operazione piuttosto semplice:

private async void OnSendMessageClicked(object sender, RoutedEventArgs e)

{

DataWriter writer = new DataWriter(socket.OutputStream);

writer.WriteString("This is a sample message");

await writer.StoreAsync();

await writer.FlushAsync();

}

Utilizziamo la classe DataWriter, che è il corrispettivo di DataReader per la scrittura di dati all'interno di uno stream. Dato che, in questo caso, non si tratta di un'operazione di lettura ma di scrittura non dovremo più usare l'InputStream dell'oggetto StreamSocket, ma l'OutputStream. In questo caso, il riferimento all'oggetto di tipo SocketStream è quello che abbiamo acquisito in precedenza quando abbiamo stabilito la connessione con il metodo ConnectAsync(). Analogamente a DataReader, anche la classe DataWriter espone diversi metodi per scrivere i tipi di dati più comuni: dato che stiamo scambiando messaggi testuali, utilizziamo il metodo WriteString(). Infine, scriviamo il dato sullo stream con il metodo StoreAsync() e lo liberiamo tramite il metodo FlushAsync().

Spostiamoci ora sul server, ovvero sull'applicazione WPF: in questo caso, dobbiamo scrivere un po' di codice in più, in quanto dobbiamo sfruttare l'approccio asincrono basato su Begin() e End() che abbiamo imparato a conoscere all'inizio del post. Innanzitutto, ci serve definire un buffer con una dimensione prefissata, all'interno del quale immagazzinare i dati in arrivo: si tratta di un array di byte.

private const int BufferSize = 1024;

private byte[] readBuffer;

Ora dobbiamo, una volta stabilita la connessione con il client, metterci in ascolto sul canale. Ecco come cambia la callback che abbiamo definito in precedenza per accettare l'arrivo di una nuova connessione:

private void AcceptCallback(IAsyncResult ar)

{

socketChannel = socket.EndAccept(ar);

readBuffer = new byte[BufferSize];

socketChannel.BeginReceive(readBuffer, 0, BufferSize, 0, ReadCallback, null);

}

Oltre ad accettare la connessione (con il metodo EndAccept()) questa volta andiamo anche ad inizializzare il buffer e a chiamare il metodo BeginReceive(), che ci permette di attivare la ricezione di eventuali dati in arrivo. Come parametri, passiamo il riferimento al buffer dove salvare questi dati e una callback (in questo caso, ReadCallback), ovvero il metodo che sarà invocato nel momento in cui la ricezione dei dati è stata completata e siamo pronti per elaborarli. Ecco come appare la definizione della callback:

private async void ReadCallback(IAsyncResult ar)

{

int received = socketChannel.EndReceive(ar);

if (received > 0)

{

string result = Encoding.ASCII.GetString(readBuffer, 0, received);

await Dispatcher.InvokeAsync(() =>

{

messages.Add(result);

});

 

}

socketChannel.BeginReceive(readBuffer, 0, BufferSize, 0, ReadCallback, null);

}

Come potete vedere, l'approccio è il medesimo visto in precedenza per l'utilizzo delle callback: chiamiamo il metodo EndReceive() passando come parametro l'oggetto di tipo IAsyncResult, così da ricevere la dimensione in byte del dato che è stato letto. Se tale dimensione è maggiore di zero, vuol dire che è arrivato qualcosa sul canale: il nostro buffer contiene dei dati, che possiamo elaborare. Dato che si tratta di un testo, riutilizziamo la classe Encoding.ASCII, questa volta per effettuare l'operazione inversa, ovvero convertire l'array di byte in una stringa tramite il metodo GetString(). Ora che abbiamo il contenuto del messaggio, possiamo elaborarlo a piacimento: in questo caso, adottiamo un approccio simile a quello dell'applicazione Windows 10, ovvero lo aggiungiamo ad una collezione di tipo ObservableCollection<string>, che viene poi mostrata nella finestra tramite un controllo ListBox. L'operazione viene eseguita tramite il Dispatcher: questo perché la callback viene eseguita su un thread secondario e, di conseguenza, non ha accesso al thread della UI.

Possiamo notare come, alla fine dell'operazione di lettura, chiamiamo nuovamente il metodo BeginReceive() della classe Socket. Questo perchè il meccanismo delle callback non è basato ad eventi, che vengono scatenati ogni qualvolta si verifica una determinata condizione. Una volta che il metodo BeginReceive() è stato invocato e ha concluso la sua esecuzione, la socket cessa di rimanere in ascolto di nuovi messaggi. Richiamandolo alla fine della callback di lettura, perciò, ci assicuriamo di poter ricevere eventuali nuovi messaggi che saranno spediti successivamente.

Un'applicazione server alternativa: Node.js

Nell'esempio precedente abbiamo creato l'applicazione server utilizzando WPF per questione di semplicità: se siamo sviluppatori di Universal Windows app, C# e il mondo .NET ci saranno sicuramente più famigliari rispetto ad altre tecnologie. La socket, però, è un canale di comunicazione agnostico e non è legato alla tecnologia con cui è sviluppato. A dimostrazione, vediamo ora brevemente come sostituire l'applicazione server in WPF con una realizzata in Node.js, la popolare tecnologia per creare applicazioni server sfruttando Javascript. Per eseguirla, avrete bisogno del runtime di Node.js attivo e funzionante sul vostro computer: potete fare riferimento a questa guida o, in alternativa, sfruttare l'installazione personalizzata di Visual Studio 2015 che, tra le altre cose, include anche tutto il necessario per sviluppare applicazioni basate su Node.js. Visual Studio stesso vi permette la creazione e il debugging di progetti Node.js, tramite l'apposita estensione che potete installare da https://github.com/Microsoft/nodejstools In alternativa, l'ottimo Visual Studio Code offre il supporto integrato per il debugging di progetti Javascript.

Ecco come appare il codice Javascript della nostra applicazione server:

// Load the TCP Library

var net = require('net');

 

// Keep track of the clients

var clients = [];

 

// Start a TCP Server

net.createServer(function (socket) {

 

// Identify this client

socket.name = socket.remoteAddress + ":" + socket.remotePort

 

// Put this new client in the list

clients.push(socket);

 

// Send a nice welcome message and announce

socket.write("Welcome " + socket.name + "\n");

 

// Remove the client from the list when it leaves

socket.on('end', function () {

clients.splice(clients.indexOf(socket), 1);

});

 

}).listen(1983);

 

 

// Put a friendly message on the terminal of the server.

console.log("Chat server running at port 1983\n");

Con il metodo require('net') otteniamo un riferimento alla libreria di Node.js per operare con le connessioni di rete. Nello specifico, tale libreria espone un metodo di nome createServer(), che ci permette di creare una socket su una specifica porta (che specifichiamo come parametro del metodo listen()). Il metodo createServer() accetta, come parametro, una funzione, che viene richiamata ogni volta un client si collega al canale. All'interno di tale funzione andiamo a:

  1. Aggiungere il riferimento al client (contenuto nell'oggetto socket) ad una collezione, che utilizziamo per mantenere l'elenco di tutti i client attivi.
  2. Inviare un messaggio al client con il nome della socket, chiamando il medoto write() sull'oggetto socket
  3. Tramite il metodo on() rimaniamo in ascolto dell'evento di terminazione della connessione: in tal caso, rimuoviamo il client dalla lista dei client attivi.

Se ora lanciassimo la nostra applicazione Windows 10 sviluppata in precedenza, vedremmo come questa riesca a collegarsi correttamente alla socket anche se il server è stato creato con una tecnologia differente: nel momento in cui premiamo il pulsante per stabilire il collegamento, riceveremo dal server Node.Js il messaggio di benvenuto con il nome della socket. Da questo punto in poi è possibile espandere ulteriormente l'applicazione Node.js ed aggiungere, ad esempio, la possibilità di effettuare una chiamata HTTP tramite browser per inviare nuovi messaggi sulla socket. Nel progetto di esempio legato a questo post troverete un esempio completo.

 

Complimenti!

Se avete seguito il post fino a qui, complimenti per la tenacia e la pazienza Spero questo lungo viaggio vi sia servito per capire al meglio come poter sfruttare la potenza delle socket all'interno di una Universal Windows app per Windows 10. Potete scaricare il progetto di esempio utilizzato nel corso dell'articolo da GitHub all'indirizzo https://github.com/qmatteoq/SocketSample-UWP Happy coding!

Dev Camps – IoT Jhb, Dbn, CT

MSDN Blogs - Mon, 02/08/2016 - 01:07
  Microsoft Dev Camp is a free and fun event for developers by developers.

Please join us for this special Dev Camp that will be presented by Microsoft technical experts.
You will learn about the Universal Windows Platform that can run across all Windows 10 devices as well as building Internet of Things solutions and using cloud backend support. Whether you haven’t looked at your most recent project in 1 month or 1 year, there is plenty to learn about what’s new - not just for a PC or a phone, but for all Windows 10 devices. That is an unprecedented opportunity of over one billion devices.

 

Durban
Date: 17 February 2016
Time: 9am - 5pm
Address: Gateway Hotel Corner Centenary Boulevard & Twilight Drive, Gateway, Durban

 

Click here to RSVP

   

Johannesburg
Date: 24 February 2016
Time: 9am - 5pm
Address: Focus Rooms 1, The Core, Leeuwkop Rd & Kikuyu rd, Sunninghill, Johannesburg

   

Click here to RSVP

   

Cape Town
Date: 02 March 2016
Time: 9am - 5pm
Address: Cape Town International Convention Centre Convention Square, 1 Lower Long St, Cape Town

 

Click here to RSVP

 

Agenda:

1.

Welcome

2.

Introduction to Windows Universal Platform

3.

Windows and IoT

4.

Azure and IoT

5.

Machine Learning and IoT

6.

Panel Discussion

 

Pages

Subscribe to Randy Riness @ SPSCC aggregator
Drupal 7 Appliance - Powered by TurnKey Linux