Как разместить приложение Silverlight 4 в приложении WPF 4?

У меня есть приложение Silverlight 4, которое я хочу использовать как приложение Kiosk. Он должен быть полноэкранным, сенсорным и, самое главное, иметь полное доверие. Я думал об этом, используя приложение WPF для размещения Silverlight XAP. Мне известно о WPF / XNA SilverlightViewport, но кажется, что это решение не обеспечивает связь между WPF и Silverlight.

Это действительно сэкономило бы мне много времени. Мне не нужно было бы обслуживать два разных приложения, которые делают одно и то же, и мне не пришлось бы развертывать сотни киосков каждый раз, когда я вносил изменения.

3 ответа

Решение

Я знаю, что это старый вопрос, но у меня есть решение.

Я делаю этот точный сценарий. Я размещаю приложение Silverlight на хосте WPF. Я использую WCF для размещения дуплексных сетевых служб TCP. Для этого у вас также должен быть HTTP-файл clientaccesspolicy.xml, который я также сам размещаю в той же службе.

Я надеюсь, что смогу объяснить достаточно, чтобы заставить мяч катиться. Я включу несколько примеров, где могу, но из-за проекта я не могу поделиться всем.

Во-первых, некоторые соображения: 1) net tcp не является безопасным между Silverlight и WPF, поскольку Silverlight (начиная с версии 4 - просто тестирование версии 5) не может выполнять безопасные соединения, поэтому вам придется свернуть собственное шифрование, если вы хотите использовать это.

2) Есть два способа сделать дуплекс WCF, один с HTTP. Метод HTTP "опрашивает" службу, чтобы определить, поступают ли какие-либо команды от хоста для клиента. Это по своей сути делает его намного медленнее, чем net tcp. Другой с net tcp (как указано ранее). Только http метод поддерживает шифрование из коробки.

3) Когда вы размещаете приложение Silverlight на хосте WPF, когда вы начинаете отлаживать, вы не сможете отлаживать ваше приложение Silverlight, так как отладчик не будет подключаться (как он его видит) к внешнему приложению Silverlight, только WPF. Чтобы обойти это, вы должны "активировать" вложение в приложение Silverlight при запуске хоста WPF.

Теперь для кода:

Интерфейс удаленного обслуживания:

using System.ServiceModel;

namespace RemoteService
{
    [ServiceContract(CallbackContract = typeof(IRemoteCallbackService))]
    public interface IRemoteService
    {
        [OperationContract]
        void TestCallback();

        // TODO: Add your service operations here
    }

    [ServiceContract]
    public interface IRemoteCallbackService
    {
        [OperationContract(IsOneWay = true)]
        void OnTestCallbackComplete();

        // TODO: Add your service operations here
    }
}

Ваш интерфейс прослушивателя политики:

using System.IO;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace RemoteService
{
    [ServiceContract]
    public interface IPolicyRetriever
    {
        [OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
        Stream GetSilverlightPolicy();

        [OperationContract, WebGet(UriTemplate = "/crossdomain.xml")]
        Stream GetFlashPolicy();
    }
}

Фактическая реализация сервиса:

using System.Text;

namespace RemoteService
{
    public class RemoteService : IRemoteService, IPolicyRetriever
    {
        IRemoteCallbackService client = null;

        public void TestCallback()
        {
            client = OperationContext.Current.GetCallbackChannel<IRemoteCallbackService>();
            client.OnTestCallbackComplete();
        }

        #region Cross Domain Policy Implementation

        private Stream StringToStream(string result)
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
            return new MemoryStream(Encoding.UTF8.GetBytes(result));
        }

        //<grant-to>
        //<resource path="/" include-subpaths="true"/>
        //<socket-resource port="4502-4534" protocol="tcp" />
        //</grant-to>

        Stream IPolicyRetriever.GetSilverlightPolicy()
        {
            string result = @"<?xml version=""1.0"" encoding=""utf-8""?><access-policy><cross-domain-access><policy><allow-from http-request-headers=""*""><domain uri=""*""/></allow-from><grant-to><resource path=""/"" include-subpaths=""true""/><socket-resource port=""4502-4534"" protocol=""tcp"" /></grant-to></policy></cross-domain-access></access-policy>";
            return StringToStream(result);
        }

        Stream IPolicyRetriever.GetFlashPolicy()
        {
            string result = @"<?xml version=""1.0""?><!DOCTYPE cross-domain-policy SYSTEM ""http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd""><cross-domain-policy><allow-access-from domain=""*"" /></cross-domain-policy>";
            return StringToStream(result);
        }

        #endregion Cross Domain Policy Implementation
    }
}

Вышеуказанное должно быть в отдельных классах в одном проекте dll, а затем на него должна ссылаться хост WPF.

И разместить его в консольном приложении (вам нужно преобразовать это в WPF):

using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using LocalService;
using RemoteService;

namespace Host
{
    internal class Program
    {
        /// <summary>
        /// Main host entry point, this starts our listeners
        /// </summary>
        /// <param name="args">The args.</param>
        private static void Main(string[] args)
        {
            // Start our listeners
            StartListeners(80, 4504, true);
        }

        /// <summary>
        /// Starts the listeners.
        /// </summary>
        private static void StartListeners(int HttpPort = 80, int NetTcpPort = 4504, bool StartRemoteService = true)
        {
            Console.WriteLine("Starting Policy Listener");

            string policyaddress = "http://" + Environment.MachineName + ":" + HttpPort.ToString();
            string locallistener = "net.tcp://" + Environment.MachineName + ":" + NetTcpPort.ToString();

            // Start our policy listener and (if required) our remote http service:
            using (System.ServiceModel.ServiceHost policyandremoteservicehost = new System.ServiceModel.ServiceHost(typeof(RemoteService.RemoteService), new Uri(policyaddress)))
            {
                policyandremoteservicehost.AddServiceEndpoint(typeof(IPolicyRetriever), new System.ServiceModel.WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());

                // if we are to start our remote service here too, then add that endpoint in:
                if (StartRemoteService)
                {
                    policyandremoteservicehost.AddServiceEndpoint(typeof(IRemoteService), new System.ServiceModel.PollingDuplexHttpBinding(), "RemoteService");
                }

                ServiceMetadataBehavior psmb = new ServiceMetadataBehavior();
                psmb.HttpGetEnabled = true;
                psmb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
                policyandremoteservicehost.Description.Behaviors.Add(psmb);
                policyandremoteservicehost.Open();


                Console.WriteLine("WCF Host Running...");
                Console.WriteLine("Press <enter> to shutdown");
                Console.ReadLine();
                Console.WriteLine("Closing connections, please wait");
                policyandremoteservicehost.Close();
                Console.WriteLine("Closed policy and remote services");
            }
        }
    }
}

Что должно дать вам над чем поработать. Startremoteservice bool может использоваться для того, чтобы просто сделать его прослушивателем файла политики, что позволит вам подключиться к удаленной службе без необходимости размещения файла политики этой удаленной службой.

Помните, что Silverlight может подключаться только к портам HTTP/HTTPS и портам TCP в диапазоне 4502-4534. Включенный файл clientaccesspolicy.xml довольно неограничен.

Я надеюсь, что это кому-то пригодится:) .

Не стесняйтесь задавать мне вопросы, если хотите, я буду следить.

Пара замечаний: вы можете обслуживать размещенный вами xap из этого решения, поэтому IIS не требуется. Вы также можете запустить свой Silverlight xap из браузера и при этом пользоваться этими услугами.

Отладочный ответ здесь: отладка Silverlight, размещенного в WPF

Лучше всего будет использовать трехуровневый подход к архитектуре, используя службы WCF/RIA и обрабатывая всю свою бизнес-логику на стороне сервера.

Если ваш клиент будет тонким и сконцентрирован в основном на представлениях и логике представлений, то замена различных клиентов будет такой же простой, как и замена любого другого компонента.

На этой ноте, если вы используете Silverlight для своего клиента, вы можете запустить его из Интернета ИЛИ как отдельное приложение, что означает, что есть несколько причин, по которым вы также захотите использовать WPF.

У меня точно такие же требования. Мое решение использует WPF для размещения Silverlight внутри элемента управления веб-браузера. Связь между ними настраивается с использованием служб WCF, которые также размещаются в WPF в одном удобном автономном пакете. Вы можете настроить ClickOnce для компонентов WPF для оптимизации обновлений. Я использую WPF для расширения Silverlight на клиентском компьютере (без необходимости повышенного доверия), предоставляя сервисы WCF для SL (например, GetComputerName,...). Единственная проблема заключается в том, что вы используете службы WCF RIA, которые не могут быть размещены за пределами IIS. Надеюсь, поможет

Другие вопросы по тегам