Отладка silverlight в приложении WPF

Я разрабатываю приложение WPF, которое содержит веб-браузер, который загружает приложение silverlight. Я хотел бы иметь возможность запустить приложение из Visual Studio (F5) и подключить отладчик к коду Silverlight. Однако мне не повезло с этим.

Лучшее, что я могу сейчас сделать - это запустить приложение без подключения, затем, как только оно будет запущено и запущено, подключить к процессу вручную с помощью silverlight в качестве указанного типа кода для отладки, и это работает. (Когда я заставляю веб-браузер загружать приложение silverlight, оно попадает в точки останова в моем коде silverlight). Я написал несколько макросов, чтобы несколько автоматизировать этот запуск / присоединение, но он все еще не самый лучший.

Я попытался указать приложение WPF в качестве внешней программы, запускаемой при запуске / отладке приложения silverlight, но Visual Studio подключается к процессу, желающему отладить управляемый код.NET.

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

3 ответа

Решение

Спасибо за идеи Брандорфа и Толстяка. Брандорф почти возвращает меня туда, куда я хотел, но требует, чтобы мое приложение SL могло работать самостоятельно. Я действительно хочу иметь только одно приложение - wpf и silverlight с отлаживаемой стороной SL.

Спустя долгое время после того, как я задал этот вопрос (я забыл, что задал этот вопрос здесь), я фактически собрал решение, которым я действительно доволен. Я использую Visual Studio Automation в WPF/.NET-стороне моего приложения, чтобы найти все работающие экземпляры Visual Studio, выяснить, какой из них создал мой exe-файл (поскольку он обычно находится в папке ниже папки vcproj/sln), а затем используйте Visual Studio Automation, чтобы подключить VS к приложению, отлаживая код Silverlight. После этого я загружаю содержимое Silverlight.

Это работает очень хорошо. В итоге вы получаете приложение, которое находит и находит отладчик, который присоединяется к себе каждый раз, когда он запускается (поэтому вы, вероятно, хотите, чтобы этот код был только в отладочной сборке, или каким-то образом можно было его отключить). Таким образом, вы просто запускаете приложение с помощью Ctrl-F5 (запуск без отладки) из Visual Studio всякий раз, когда вы хотите отладить сторону Silverlight.

Вот мой код:

#if DEBUG

using System;
using System.Collections.Generic;
using System.Collections;
using System.Runtime.InteropServices;
using System.IO;

namespace Launcher
{
    //The core methods in this class to find all running instances of VS are
    //taken/inspired from
    //http://www.codeproject.com/KB/cs/automatingvisualstudio.aspx
    class DebuggingAutomation
    {
        [DllImport("ole32.dll")]
        private static extern int GetRunningObjectTable(int reserved,
                                  out UCOMIRunningObjectTable prot);

        [DllImport("ole32.dll")]
        private static extern int CreateBindCtx(int reserved,
                                      out UCOMIBindCtx ppbc);
        ///<summary>
        ///Get a snapshot of the running object table (ROT).
        ///</summary>
        ///<returns>
        ///A hashtable mapping the name of the object
        ///in the ROT to the corresponding object
        ///</returns>
        private static Hashtable GetRunningObjectTable()
        {
            Hashtable result = new Hashtable();

            int numFetched;
            UCOMIRunningObjectTable runningObjectTable;
            UCOMIEnumMoniker monikerEnumerator;
            UCOMIMoniker[] monikers = new UCOMIMoniker[1];

            GetRunningObjectTable(0, out runningObjectTable);
            runningObjectTable.EnumRunning(out monikerEnumerator);
            monikerEnumerator.Reset();

            while (monikerEnumerator.Next(1, monikers, out numFetched) == 0)
            {
                UCOMIBindCtx ctx;
                CreateBindCtx(0, out ctx);

                string runningObjectName;
                monikers[0].GetDisplayName(ctx, null, out runningObjectName);

                object runningObjectVal;
                runningObjectTable.GetObject(monikers[0], out runningObjectVal);

                result[runningObjectName] = runningObjectVal;
            }

            return result;
        }

        /// <summary>
        /// Get a table of the currently running instances of the Visual Studio .NET IDE.
        /// </summary>
        /// <param name="openSolutionsOnly">
        /// Only return instances that have opened a solution
        /// </param>
        /// <returns>
        /// A list of the ides (as DTE objects) present in
        /// in the running object table to the corresponding DTE object
        /// </returns>
        private static List<EnvDTE.DTE> GetIDEInstances(bool openSolutionsOnly)
        {
            var runningIDEInstances = new List<EnvDTE.DTE>();
            Hashtable runningObjects = GetRunningObjectTable();

            IDictionaryEnumerator rotEnumerator = runningObjects.GetEnumerator();
            while (rotEnumerator.MoveNext())
            {
                string candidateName = (string)rotEnumerator.Key;
                if (!candidateName.StartsWith("!VisualStudio.DTE"))
                    continue;

                EnvDTE.DTE ide = rotEnumerator.Value as EnvDTE.DTE;
                if (ide == null)
                    continue;

                if (openSolutionsOnly)
                {
                    try
                    {
                        string solutionFile = ide.Solution.FullName;
                        if (!String.IsNullOrEmpty(solutionFile))
                        {
                            runningIDEInstances.Add(ide);
                        }
                    }
                    catch { }
                }
                else
                {
                    runningIDEInstances.Add(ide);
                }
            }
            return runningIDEInstances;
        }

        internal static void AttachDebuggerIfPossible()
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                //Probably debugging host (Desktop .NET side), so don't try to attach to silverlight side
                return;
            }
            var ides = GetIDEInstances(true);
            var fullPathToAssembly = System.Reflection.Assembly.GetExecutingAssembly().Location;
            var potentials = new List<EnvDTE.DTE>();
            foreach (var ide in ides)
            {
                var solutionPath = ide.Solution.FullName;
                var topLevelSolutionDir = Path.GetDirectoryName(solutionPath);
                var assemblyName = fullPathToAssembly;
                if (assemblyName.StartsWith(topLevelSolutionDir, StringComparison.OrdinalIgnoreCase))
                {
                    potentials.Add(ide);
                }
            }

            EnvDTE.DTE chosenIde = null;
            //If you have multiple ides open that can match your exe, you can come up with a scheme to pick a particular one
            //(eg, put a file like solution.sln.pickme next to the solution whose ide you want to debug). If this is not a
            //concern, just pick the first match.
            if (potentials.Count > 0)
            {
                chosenIde = potentials[0];
            }
            var dbg = chosenIde != null ? (EnvDTE80.Debugger2)chosenIde.Debugger : null;

            if (dbg != null)
            {
                var trans = dbg.Transports.Item("Default");

                var proc = (EnvDTE80.Process2)dbg.GetProcesses(trans, System.Environment.MachineName).Item(Path.GetFileName(fullPathToAssembly));
                var engines = new EnvDTE80.Engine[1];
                engines[0] = trans.Engines.Item("Silverlight");

                proc.Attach2(engines);
            }
        }
    }
}
#endif 

Если вы не можете добавить проект Silverlight в свое решение (которое автоматически начнет отладку), вы можете использовать этот совет. Он загрузит оба проекта одновременно

http://saraford.net/2008/07/28/did-you-know-you-can-start-debugging-multiple-projects-268/

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

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