Поделиться через


Реализация поставщика веб-каналов в приложении Windows на C#

Примечание.

Некоторые сведения относятся к предварительной версии продукта, в которую перед коммерческим выпуском могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В этой статье описывается создание простого поставщика веб-каналов, который регистрирует URI содержимого веб-канала и реализует интерфейс IFeedProvider . Методы этого интерфейса вызываются доска мини-приложений для запроса пользовательских параметров строки запроса, как правило, для поддержки сценариев проверки подлинности. Поставщики веб-каналов могут поддерживать один веб-канал или несколько веб-каналов.

Сведения о реализации поставщика веб-каналов с помощью C++/WinRT см. в разделе "Реализация поставщика веб-каналов" в приложении win32 (C++/WinRT).

Необходимые компоненты

  • Устройство должно быть включено в режиме разработчика. Дополнительные сведения см. в разделе "Включение устройства для разработки".
  • Visual Studio 2022 или более поздней версии с рабочей нагрузкой разработки универсальная платформа Windows.

Создание консольного приложения C#

В Visual Studio создайте проект . В диалоговом окне "Создание проекта" установите для фильтра языка значение "C#" и фильтр платформы в Windows, а затем выберите шаблон проекта консольного приложения. Назовите новый проект ExampleFeedProvider. В этом пошаговом руководстве убедитесь, что решение и проект place в том же каталоге сняты. При появлении запроса задайте для целевой версии .NET значение 6.0.

Когда проект загружается, в Обозреватель решений щелкните правой кнопкой мыши имя проекта и выберите "Свойства". На странице "Общие" прокрутите вниз до целевой ОС и выберите "Windows". В разделе "Целевая версия ОС" выберите версию 10.022631.2787 или более поздней.

Обратите внимание, что в этом пошаговом руководстве используется консольное приложение, отображающее окно консоли при активации веб-канала для упрощения отладки. Когда вы будете готовы опубликовать приложение поставщика веб-канала, вы можете преобразовать консольное приложение в приложение Windows, выполнив действия, описанные в разделе "Преобразование консольного приложения в приложение Windows".

Добавление ссылок на пакет NuGet пакета Sdk для приложений Windows

В этом примере используется последний стабильный пакет Пакета NuGet для приложений Windows. В Обозреватель решений щелкните правой кнопкой мыши зависимости и выберите пункт "Управление пакетами NuGet...". В диспетчере пакетов NuGet перейдите на вкладку "Обзор" и найдите "Microsoft.WindowsAppSDK". Выберите последнюю стабильную версию в раскрывающемся списке "Версия" , а затем нажмите кнопку "Установить".

Добавление класса FeedProvider для обработки операций веб-канала

В Visual Studio щелкните проект правой ExampleFeedProvider кнопкой мыши в Обозреватель решений и выберите "Класс надстройки>". В диалоговом окне "Добавление класса" назовите класс "FeedProvider" и нажмите кнопку "Добавить". В созданном файле FeedProvider.cs обновите определение класса, чтобы указать, что он реализует интерфейс IFeedProvider .

Создайте CLSID, который будет использоваться для идентификации поставщика веб-канала для активации COM. Создайте GUID в Visual Studio, перейдя в раздел "Сервис-создание> GUID". Сохраните этот GUID в текстовом файле, который будет использоваться позже при упаковке приложения поставщика веб-каналов. Замените GUID в заметках для класса FeedProvider , показанного в следующем примере.

// FeedProvider.cs
using Microsoft.Windows.Widgets.Feeds.Providers;
...
[ComVisible(true)]
[ComDefaultInterface(typeof(IFeedProvider))]
[Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]
public sealed class FeedProvider : IFeedProvider

Реализация методов IFeedProvider

В следующих нескольких разделах мы реализуем методы интерфейса IFeedProvider .

Примечание.

Объекты, передаваемые в методы обратного вызова интерфейса IFeedProvider , гарантированно допустимы только в обратном вызове. Не следует хранить ссылки на эти объекты, так как их поведение вне контекста обратного вызова не определено.

OnFeedProviderEnabled

Метод OnFeedProviderEnabled вызывается, когда веб-канал, связанный с поставщиком, создается узлом Мини-приложения Board. В реализации этого метода создайте строку запроса с параметрами, которые будут переданы URL-адресу, который предоставляет содержимое веб-канала, включая все необходимые маркеры проверки подлинности. Создайте экземпляр CustomQueryParametersUpdateOptions, передавая в feedProviderDefinitionId из аргов событий, определяющих веб-канал, включенный и строку запроса. Получите по умолчанию FeedManager и вызовите SetCustomQueryParameters , чтобы зарегистрировать параметры строки запроса в Board мини-приложений.

// FeedProvider.cs

public void OnFeedProviderEnabled(FeedProviderEnabledArgs args)
{
    Console.WriteLine($"{args.FeedProviderDefinitionId} feed provider was enabled.");
    var updateOptions = new CustomQueryParametersUpdateOptions(args.FeedProviderDefinitionId, "param1&param2");
    FeedManager.GetDefault().SetCustomQueryParameters(updateOptions);
}

OnFeedProviderDisabled

OnFeedProviderDisabled вызывается при отключении всех веб-каналов для этого поставщика. Поставщики веб-каналов не требуются для выполнения каких-либо действий в ответ на этот вызов метода. Вызов метода можно использовать для целей телеметрии или обновления параметров строки запроса или отзыва маркеров проверки подлинности при необходимости. Если приложение поддерживает только одного поставщика веб-каналов или если все поставщики веб-каналов, поддерживаемые приложением, были отключены, приложение может выйти в ответ на этот обратный вызов.

// FeedProvider.cs
public void OnFeedProviderDisabled(FeedProviderDisabledArgs args)
{
    Console.WriteLine($"{args.FeedProviderDefinitionId} feed provider was disabled.");
}

OnFeedEnabled, OnFeedDisabled

OnFeedEnabled и OnFeedDisabled вызываются советом мини-приложений при включении или отключении веб-канала. Поставщики веб-каналов не требуются для выполнения каких-либо действий в ответ на эти вызовы метода. Вызов метода можно использовать для целей телеметрии или обновления параметров строки запроса или отзыва маркеров проверки подлинности при необходимости.

// FeedProvider.cs
public void OnFeedEnabled(FeedEnabledArgs args)
{
    Console.WriteLine($"{args.FeedDefinitionId} feed was enabled.");
}

// FeedProvider.cs
public void OnFeedDisabled(FeedDisabledArgs args)
{
    Console.WriteLine($"{args.FeedDefinitionId} feed was disabled.");
}

OnCustomQueryParametersRequested

OnCustomQueryParametersRequested возникает, когда доска мини-приложений определяет, что пользовательские параметры запроса, связанные с поставщиком веб-канала, необходимо обновить. Например, этот метод может возникать, если операция получения содержимого веб-канала из удаленной веб-службы завершается ошибкой. Свойство FeedProviderDefinitionId объекта CustomQueryParametersRequestedArgs , переданное в этот метод, указывает канал, для которого запрашиваются параметры строки запроса. Поставщик должен повторно создать строку запроса и передать ее обратно в доску мини-приложений, вызвав SetCustomQueryParameters.

// FeedProvider.cs

public void OnCustomQueryParametersRequested(CustomQueryParametersRequestedArgs args)
{
    Console.WriteLine($"CustomQueryParamaters were requested for {args.FeedProviderDefinitionId}.");
    var updateOptions = new CustomQueryParametersUpdateOptions(args.FeedProviderDefinitionId, "param1&param2");
    FeedManager.GetDefault().SetCustomQueryParameters(updateOptions);
}

Реализация фабрики классов, которая будет создавать экземпляр FeedProvider по запросу

Чтобы узел веб-канала взаимодействовал с нашим поставщиком веб-каналов, необходимо вызвать CoRegisterClassObject. Для этой функции требуется создать реализацию IClassFactory , которая создаст объект класса для класса FeedProvider . Мы реализуем фабрику классов в автономном вспомогательном классе.

В Visual Studio щелкните проект правой ExampleFeedProvider кнопкой мыши в Обозреватель решений и выберите "Класс надстройки>". В диалоговом окне "Добавить класс" назовите класс "FactoryHelper" и нажмите кнопку "Добавить".

Замените содержимое файла FactoryHelper.cs следующим кодом. Этот код определяет интерфейс IClassFactory и реализует два метода CreateInstance и LockServer. Этот код является типичным шаблоном для реализации фабрики классов и не зависит от функциональности поставщика веб-каналов, за исключением того, что созданный объект класса реализует интерфейс IFeedProvider .

// FactoryHelper.cs
using Microsoft.Windows.Widgets.Feeds.Providers;
using System.Runtime.InteropServices;
using WinRT;

namespace ExampleFeedProvider
{
    namespace Com
    {
        static class Guids
        {
            public const string IClassFactory = "00000001-0000-0000-C000-000000000046";
            public const string IUnknown = "00000000-0000-0000-C000-000000000046";
        }

        [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(Guids.IClassFactory)]
        internal interface IClassFactory
        {
            [PreserveSig]
            int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);
            [PreserveSig]
            int LockServer(bool fLock);
        }

        static class ClassObject
        {
            public static void Register(Guid clsid, object pUnk, out uint cookie)
            {
                [DllImport("ole32.dll")]
                static extern int CoRegisterClassObject(
                    [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
                    [MarshalAs(UnmanagedType.IUnknown)] object pUnk,
                    uint dwClsContext,
                    uint flags,
                    out uint lpdwRegister);

                int result = CoRegisterClassObject(clsid, pUnk, 0x4, 0x1, out cookie);
                if (result != 0)
                {
                    Marshal.ThrowExceptionForHR(result);
                }
            }

            public static int Revoke(uint cookie)
            {
                [DllImport("ole32.dll")]
                static extern int CoRevokeClassObject(uint dwRegister);

                return CoRevokeClassObject(cookie);
            }
        }
    }

    internal class FeedProviderFactory<T> : Com.IClassFactory
            where T : IFeedProvider, new()
    {
        public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)
        {
            ppvObject = IntPtr.Zero;

            if (pUnkOuter != IntPtr.Zero)
            {
                Marshal.ThrowExceptionForHR(CLASS_E_NOAGGREGATION);
            }

            if (riid == typeof(T).GUID || riid == Guid.Parse(Com.Guids.IUnknown))
            {
                // Create the instance of the .NET object
                ppvObject = MarshalInspectable<IFeedProvider>.FromManaged(new T());
            }
            else
            {
                // The object that ppvObject points to does not support the
                // interface identified by riid.
                Marshal.ThrowExceptionForHR(E_NOINTERFACE);
            }

            return 0;
        }

        int Com.IClassFactory.LockServer(bool fLock)
        {
            return 0;
        }

        private const int CLASS_E_NOAGGREGATION = -2147221232;
        private const int E_NOINTERFACE = -2147467262;
    }
}

Регистрация объекта класса поставщика веб-канала с помощью OLE

В файле Program.cs для нашего исполняемого файла мы вызовем CoRegisterClassObject для регистрации поставщика веб-канала в OLE, чтобы доска мини-приложений могли взаимодействовать с ним. Замените содержимое Program.cs приведенным ниже кодом. Для регистрации вспомогательного класса FeedProviderFactory используется интерфейс FeedProviderFactory, определенный на предыдущем шаге. В целях отладки в этом примере вызывается GetEnabledFeedProviders в экземпляре FeedManager по умолчанию, чтобы получить список объектов FeedProviderInfo, представляющих включенных поставщиков веб-каналов. Он цикличен через включенных поставщиков веб-каналов, используя свойство EnabledFeedDefinitionIds для перечисления всех идентификаторов веб-каналов с поддержкой.

// Program.cs

using Microsoft.Windows.Widgets.Feeds.Providers;
using Microsoft.Windows.Widgets.Providers;
using System; 
using System.Runtime.InteropServices;

namespace ExampleFeedProvider
{

    public static class Program
    {
        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();

        [MTAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("FeedProvider Starting...");
            if (args.Length > 0 && args[0] == "-RegisterProcessAsComServer")
            {
                WinRT.ComWrappersSupport.InitializeComWrappers();

                uint registrationHandle;
                var factory = new FeedProviderFactory<FeedProvider>();
                Com.ClassObject.Register(typeof(FeedProvider).GUID, factory, out registrationHandle);

                Console.WriteLine("Feed Provider registered.");

                var existingFeedProviders = FeedManager.GetDefault().GetEnabledFeedProviders();
                if (existingFeedProviders != null)
                {
                    Console.WriteLine($"There are {existingFeedProviders.Length} FeedProviders currently outstanding:");
                    foreach (var feedProvider in existingFeedProviders)
                    {
                        Console.WriteLine($"  ProviderId: {feedProvider.FeedProviderDefinitionId}, DefinitionIds: ");
                        var m = WidgetManager.GetDefault().GetWidgetIds();
                        if (feedProvider.EnabledFeedDefinitionIds != null)
                        {
                            foreach (var enabledFeedId in feedProvider.EnabledFeedDefinitionIds)
                            {
                                Console.WriteLine($" {enabledFeedId} ");
                            }
                        }
                    }
                }
                if (GetConsoleWindow() != IntPtr.Zero)
                {
                    Console.WriteLine("Press ENTER to exit.");
                    Console.ReadLine();
                }
                else
                {
                    while (true)
                    {
                        // You should fire an event when all the outstanding
                        // FeedProviders have been disabled and exit the app.
                    }
                }
            }
            else
            {
                Console.WriteLine("Not being launched to service Feed Provider... exiting.");
            }
        }
    }
}

Обратите внимание, что этот пример кода импортирует функцию GetConsoleWindow , чтобы определить, работает ли приложение в качестве консольного приложения, поведение по умолчанию для этого пошагового руководства. Если функция возвращает допустимый указатель, мы записываем сведения об отладке в консоль. В противном случае приложение работает в качестве приложения Для Windows. В этом случае мы ждем события, заданного в методе OnFeedProviderDisabled , когда список включенных поставщиков веб-каналов пуст, и мы выходим из приложения. Сведения о преобразовании примера консольного приложения в приложение Windows см. в статье "Преобразование консольного приложения в приложение Windows".

Упаковка приложения поставщика веб-каналов

В текущем выпуске только упакованные приложения можно зарегистрировать в качестве поставщиков веб-каналов. Ниже описано, как упаковать приложение и обновить манифест приложения, чтобы зарегистрировать приложение в качестве поставщика веб-канала.

Создание проекта упаковки MSIX

В Обозреватель решений щелкните решение правой кнопкой мыши и выберите "Добавить> новый проект...". В диалоговом окне "Добавление нового проекта" выберите шаблон "Проект упаковки приложений Windows" и нажмите кнопку "Далее". Задайте для имени проекта значение ExampleFeedProviderPackage и нажмите кнопку "Создать". При появлении запроса задайте целевую версию сборки 22621 или более поздней и нажмите кнопку ОК. Затем щелкните правой кнопкой мыши проект ExampleFeedProviderPackage и выберите ссылку add-Project>. Выберите проект ExampleFeedProvider и нажмите кнопку "ОК".

Добавление ссылки на пакет sdk для приложений Windows в проект упаковки

Необходимо добавить ссылку на пакет nuget пакета sdk для приложений Windows в проект упаковки MSIX. В Обозреватель решений дважды щелкните проект ExampleFeedProviderPackage, чтобы открыть файл ExampleFeedProviderPackage.wapproj. Добавьте следующий xml-код в элемент Project .

<!--ExampleWidgetProviderPackage.wapproj-->
<ItemGroup>
    <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231116003-experimentalpr">
        <IncludeAssets>build</IncludeAssets>
    </PackageReference>  
</ItemGroup>

Примечание.

Убедитесь, что версия , указанная в элементе PackageReference , соответствует последней стабильной версии, на которая ссылается на предыдущий шаг.

Если на компьютере уже установлена правильная версия пакета SDK для приложений Windows, и вы не хотите упаковывать среду выполнения пакета в пакет, можно указать зависимость пакета в файле Package.appxmanifest для проекта ExampleFeedProviderPackage.

<!--Package.appxmanifest-->
...
<Dependencies>
...
    <PackageDependency Name="Microsoft.WindowsAppRuntime.1.5.233430000-experimental1" MinVersion="2000.638.7.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
...
</Dependencies>
...

Обновление манифеста пакета

В Обозреватель решений щелкните файл правой кнопкой мыши Package.appxmanifest и выберите команду Просмотреть код, чтобы открыть XML-файл манифеста. Затем необходимо добавить некоторые объявления пространства имен для расширений пакета приложения, которые мы будем использовать. Добавьте следующие определения пространства имен в элемент package верхнего уровня.

<!-- Package.appmanifest -->
<Package
  ...
  xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"

В элементе Application создайте пустой элемент с именем Extensions. Убедитесь, что это происходит после закрывающего тега uap :VisualElements.

<!-- Package.appxmanifest -->
<Application>
...
    <Extensions>

    </Extensions>
</Application>

Первым расширением , который необходимо добавить, является расширение ComServer . Это регистрирует точку входа исполняемого файла в ОС. Это расширение является упаковаемым приложением, эквивалентным регистрации COM-сервера, задав раздел реестра и не относясь к поставщикам мини-приложений. Добавьте следующий элемент com:Extension в качестве дочернего элемента Extensions . Измените GUID в атрибуте идентификатора элемента com:Class на GUID, созданный на предыдущем шаге при определении класса FeedProvider.

<!-- Package.appxmanifest -->
<Extensions>
    <com:Extension Category="windows.comServer">
        <com:ComServer>
            <com:ExeServer Executable="ExampleFeedProvider\ExampleFeedProvider.exe" Arguments="-RegisterProcessAsComServer" DisplayName="C# Feed Provider App">
                <com:Class Id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" DisplayName="FeedProvider" />
            </com:ExeServer>
        </com:ComServer>
    </com:Extension>
</Extensions>


Затем добавьте расширение, которое регистрирует приложение в качестве поставщика веб-канала. Вставьте элемент uap3:Extension в следующий фрагмент кода в качестве дочернего элемента Extensions. Обязательно замените атрибут ClassId элемента COM идентификатором GUID, который использовался на предыдущих шагах.

<!-- Package.appxmanifest -->
<Extensions>
    ...
    <uap3:Extension Category="windows.appExtension">
        <uap3:AppExtension Name="com.microsoft.windows.widgets.feeds" DisplayName="ContosoFeed" Id="com.examplewidgets.examplefeed" PublicFolder="Public">
            <uap3:Properties>
                <FeedProvider Icon="ms-appx:Assets\StoreLogo.png" Description="FeedDescription">
                    <Activation>
                        <!-- Apps exports COM interface which implements IFeedProvider -->
                        <CreateInstance ClassId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
                    </Activation>
                    <Definitions>
                        <Definition Id="Contoso_Feed"
                            DisplayName="Contoso_Feed Feed"
                            Description="Feed representing Contoso"
                            ContentUri="https://www.contoso.com/"
                            Icon="ms-appx:Images\StoreLogo.png">
                        </Definition>
                        <Definition Id="Fabrikam_Feed"
                            DisplayName="Fabrikam Feed"
                            Description="Feed representing Example"
                            ContentUri="https://www.fabrikam.com/"
                            Icon="ms-appx:Images\StoreLogo.png">
                        </Definition>
                    </Definitions>
                </FeedProvider>
            </uap3:Properties>
        </uap3:AppExtension>
    </uap3:Extension>
</Extensions>

Подробные описания и сведения о форматировании всех этих элементов см . в формате XML манифеста пакета поставщика веб-канала.

Тестирование поставщика веб-канала

Убедитесь, что вы выбрали архитектуру, соответствующую компьютеру разработки, в раскрывающемся списке "Платформы решений", например "x64". В Обозреватель решений щелкните решение правой кнопкой мыши и выберите команду "Создать решение". После этого щелкните правой кнопкой мыши имя ExampleWidgetProviderPackage и выберите "Развернуть". Консольное приложение должно запускаться при развертывании, и вы увидите, что веб-каналы включены в выходных данных консоли. Откройте доску мини-приложений и вы увидите новые веб-каналы на вкладках в верхней части раздела веб-каналов.

Отладка поставщика веб-канала

После закрепления веб-каналов платформа мини-приложений запустит приложение поставщика веб-каналов для получения и отправки соответствующих сведений о веб-канале. Чтобы выполнить отладку запущенного веб-канала, можно подключить отладчик к приложению поставщика веб-каналов или настроить Visual Studio для автоматической отладки процесса поставщика веб-каналов после его запуска.

Чтобы подключиться к выполняемой процедуре, выполните следующие действия:

  1. В Visual Studio щелкните "Отладка—> присоединение к процессу".
  2. Отфильтруйте процессы и найдите нужное приложение поставщика веб-каналов.
  3. Подключение отладчика.

Чтобы автоматически подключить отладчик к процессу при первоначальном запуске:

  1. В Visual Studio щелкните "Отладка "> Другие целевые объекты отладки —> отладка установленного пакета приложения".
  2. Отфильтруйте пакеты и найдите нужный пакет поставщика веб-каналов.
  3. Установите его и установите флажок, который говорит, что не запускается, но отлаживать код при запуске.
  4. Нажмите кнопку Присоединить.

Преобразование консольного приложения в приложение Windows

Чтобы преобразовать консольное приложение, созданное в этом пошаговом руководстве, в приложение Windows щелкните правой кнопкой мыши проект ExampleFeedProvider в Обозреватель решений и выберите "Свойства". В разделе "Общие приложения>" измените тип выходных данных с "Консольное приложение" на "Приложение Windows".

Снимок экрана: свойства проекта поставщика веб-канала C# с типом выходных данных, заданным для приложения Windows

Публикация приложения поставщика веб-каналов

После разработки и тестирования поставщика веб-каналов вы можете опубликовать приложение в Microsoft Store, чтобы пользователи могли устанавливать веб-каналы на своих устройствах. Пошаговые инструкции по публикации приложения см. в статье "Публикация приложения в Microsoft Store".

Коллекция хранилища веб-каналов

После публикации приложения в Microsoft Store вы можете запросить включение приложения в коллекцию магазинов веб-каналов, которая помогает пользователям обнаруживать приложения, которые содержат веб-каналы Windows. Чтобы отправить запрос, см. статью "Отправить веб-канал или доску" для добавления в коллекцию Магазинов.