Does Visual Studio have a Protocol Handler that includes a command to open a specific file?
They have one for Git clone, as described in Announcing the GitHub Extension for Visual Studio:
The Open in Visual Studio button [in GitHub] calls a new protocol handler called “git-client://”. We designed this new generic protocol together with GitHub to allow a website pass standard Git operations to any IDE
Essentially what I want to do is described in this GitHub Issues:
When I click on the Button, Visual Studio should open the specific file (preferably with the correct Solution loaded as well).
If this isn't possible directly with Protocol Handlers, could it be done as a Visual Studio Extensions with a Web View that would achieve the same purpose (ie allow opening files from a Web Page)?
I was able to get close enough to what I wanted by creating a Visual Studio plugin with a self hosted Owin server exposing a basic WebApi.
This allowed me to open files from a browser with a link like: http://localhost:9000/VisualStudioApi/OpenFile?Path=.\Url\Escaped\Path\Relative\To\Solution\File
Any web server hosting this button would need to hardcode the links to http://localhost:9000
, which brings up an issue of having multiple Visual Studio instances running, so there would need to be some logic about how to map a .sln file to a known port. But absent an official Visual Studio solution, this gets the job done for the most part.
In case this helps someone in the future, here are the code snippets:
VS Package
[ComVisible(true)]
[Guid("B77F7C65-0F9F-422A-A897-C06FDAEC9604")]
[ProvideObject(typeof(InitializerPackage))]
[ProvideAutoLoad(UIContextGuids80.SolutionExists)]
public class InitializerPackage : Package
{
protected override void Initialize()
{
base.Initialize();
//Get copy of current DTE
var dte = (DTE)GetService(typeof(DTE));
var dte2 = dte as DTE2;
dte2.Events.SolutionEvents.Opened += () =>
OwinVisualStudioApiListenerManager.StartServer(dte2);
dte2.Events.SolutionEvents.AfterClosing += () =>
OwinVisualStudioApiListenerManager.StopServer();
}
}
Owin Initializer
public static class OwinVisualStudioApiListenerManager
{
private static IDisposable _runningServer;
public static DTE2 VisualStudioApi { get; set; }
public static void StartServer(DTE2 visualStudioApi)
{
if (null != _runningServer)
_runningServer.Dispose();
VisualStudioApi = visualStudioApi;
//nothing fancy about OwinStartup
//see github file http://tinyurl.com/zt2bm8b
_runningServer = WebApp.Start<OwinStartup>("http://localhost:9000");
}
public static void StopServer()
{
if (null != _runningServer)
_runningServer.Dispose();
VisualStudioApi = null;
}
}
WebApi
public class VisualStudioApiController : ApiController
{
// GET /VisualStudioApi/OpenFile/?path=
[HttpGet]
public string OpenFile(string path)
{
var fullPath = Path.Combine(
Path.GetDirectoryName(
OwinVisualStudioApiListenerManager.VisualStudioApi.Solution.FullName),
HttpUtility.UrlDecode(path));
//http://stackoverflow.com/q/5039226/1224069
OwinVisualStudioApiListenerManager.VisualStudioApi
.ExecuteCommand(
"File.OpenFile",
fullPath);
return "success";
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With