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

Примечание.

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

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

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

Требования

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

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

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

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

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

Добавление ссылок на пакет NuGet Windows App SDK

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

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

В Visual Studio щелкните правой кнопкой мыши по проекту в Обозревателе решений и выберите Класс. В диалоговом окне "Добавление класса" назовите класс "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 вызывается, когда веб-канал, связанный с поставщиком, создается хостом Widgets Board. В реализации этого метода создайте строку запроса с параметрами, которые будут переданы URL-адресу, который предоставляет содержимое веб-канала, включая все необходимые маркеры проверки подлинности. Создайте экземпляр CustomQueryParametersUpdateOptions, передавая в FeedProviderDefinitionId из аргумента события, который определяет включенный веб-канал и строку запроса. Получите экземпляр по умолчанию FeedManager и вызовите SetCustomQueryParameters, чтобы зарегистрировать параметры строки запроса на доске виджетов.

// 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 вызывается в доске Widgets, когда все веб-каналы для этого поставщика отключены. Поставщики веб-каналов не обязаны выполнять какие-либо действия в ответ на вызов этого метода. Вызов метода можно использовать для целей телеметрии или обновления параметров строки запроса или отзыва маркеров проверки подлинности при необходимости. Если приложение поддерживает только одного поставщика веб-каналов или если все поставщики веб-каналов, поддерживаемые приложением, были отключены, приложение может выйти в ответ на этот обратный вызов.

// 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 щелкните правой кнопкой мыши по проекту в Обозревателе решений и выберите Класс. В диалоговом окне "Добавить класс" назовите класс "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, чтобы Widgets Board мог взаимодействовать с ним. Замените содержимое 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 и выберите Добавить-ссылку на проект. Выберите проект ExampleFeedProvider и нажмите кнопку "ОК".

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

Необходимо добавить ссылку на пакет NuGet Windows App SDK в проект упаковки 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 в атрибуте Id элемента 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. Чтобы отправить запрос, см. «Отправка веб-канала или доски для добавления в коллекцию магазина».