Creating a Custom URL Protocol in .NET
Tags: dotnet, csharp, tutorial
Published: 2023-08-12 13:11:11

> You open a Teams link and it prompts you to open the Teams Desktop Application, and you sit back and wonder how this works.

Well wonder no more !  This process is possible because of _URL protocols_ - similar to how Windows sets the default web browser or the default email app. You have probably seen it in actions a few times from apps like Teams or Zoom. Windows has a few of these built in, but we can create our own _custom protocols_ too. 

You can create these by manually adding a Reg Key but we'll do this via .NET. 

We'll create a simple app, and a custom protocol that will open this app when a user clicks on a URL with the protocol.   

_Lets go !_

## Setup 

Lets start with creating a desktop application - for simplicity I've chosen a WPF app. Open Visual Studio with Administrator privilege's ( I'll explain later ) and create a new WPF project.  

## App Startup 
In the App.xaml.cs file create a new method called `RegisterProtocol()` . We'll run this on startup to create our protocol. 

We'll need to do check if the protocol exists, and if not then create it. 

We set the name of our protocol and assign to a variable.
```csharp
string customProtocol = "CustomProtocol";
```

Then add we check if a Registry Key exists for this value : 
```csharp
RegistryKey key = Registry.ClassesRoot.OpenSubKey(customProtocol);
if (key == null){
...
}
```
If the key is null then we will have to create one. 

```csharp
if (key == null) {
    key = Registry.ClassesRoot.CreateSubKey(customProtocol);
    key.SetValue(string.Empty, "URL: " + customProtocol);
    key.SetValue("URL Protocol", string.Empty);

    key = key.CreateSubKey(@"shell\open\command");
    key.SetValue(string.Empty, applicationPath + " " + "%1");    
    key.Close();
}
```
Now to explain it a bit. 

1. `key = Registry.ClassesRoot.CreateSubKey(customProtocol);`
This line creates a new subkey in the HKEY_CLASSES_ROOT registry. This is where file associations and protocol handlers are registered. 

2. `key.SetValue(string.Empty, "URL: " + customProtocol);`
This line sets a value for the subkey we just created. The value's name is an empty string (indicating the default value for the key), and the value's data is a string that specifies the type of URL and the custom protocol name.

3. `key.SetValue("URL Protocol", string.Empty);`
This line sets a value named "URL Protocol" within the same subkey.

4. `key = key.CreateSubKey(@"shell\open\command");`
This line creates a new subkey within our key. The subkey is named "shell\open\command". This is where you specify the command to be executed when a URL matching our protocol is opened. 

5. `key.SetValue(string.Empty, applicationPath + " " + "%1");`
This line sets the default value for the shell command key we just created. The data is the filepath to the EXE for our application, and %1 represents any parameters sent.

6. `key.Close();`
We simply close the key to finish. 

We now have one last thing before the key can be registered.  We have to make sure the application has the correct privilege's to edit the registry. 

In your app.manifest file ( add one if you dont have one )  
Add the below: 
```xml
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
	<requestedExecutionLevel level="requireAdministrator" />
 </requestedPrivileges>
```

This will make the application ask the user for admin the privilege's that we need to create the key. 

## GUI 
Next up we'll edit the application to display any arguments that are passed to the app when opened via the custom protocol. 
We don't need to do this part, but it will show you that any parameters you sent are indeed working ! 

In your MainWindow.xaml.cs add the below string to display the arguments passed in.
```csharp
public string ArgumentsText
    {
        get { return argumentsTextBlock.Text; }
        set { argumentsTextBlock.Text = value; }
 }
```
And within the MainWindow.xaml file add a textblock to display the string: 
```xaml
<TextBlock x:Name="argumentsTextBlock" Margin="10" />
```

Next we need to edit the app.xaml.cs to pass the arguments into the MainWindow:

Edit the OnStartup like so: 
```csharp
protected override void OnStartup(StartupEventArgs e)
    {
       base.OnStartup(e);
       RegisterProtocol();

        MainWindow mainWindow = new MainWindow();
        if (e.Args.Length > 0)
        {
           string arguments = string.Join(", ", e.Args);
           mainWindow.ArgumentsText = "Arguments: " + arguments;
       }
        else
        {
            mainWindow.ArgumentsText = "No arguments provided.";
        }

       mainWindow.Show();
   }
```

We first call our `RegisterProtocol` method and then check for any arguments passed in on startup before manually creating our main window. 

Now you can publish the application and click the EXE to run it.
You should see something like the below image - 
![Default App Open](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k1vnw677f8zyxubvckix.png)

This is what we expect - there are no parameters passed when clicking the EXE. 

## Web 
Next we're going to create a simple HTML file to simulate opening our protocol from the web. 

```html
<!DOCTYPE html>
<html>
<head>
    <title>Custom Protocol Test</title>
</head>
<body>
    <p>Click the link below to test your custom protocol:</p>

    <a href="CustomProtocol://myargument">Test Custom Protocol</a> 

</body>
</html>
```  
Like I said - pretty simple. The value for the href is the name of your protocol followed by '://' along with any parameters you want to pass - I am passing in the string "myargument" . 

## In Action
Lets open up the file in browser and try it out. 

Click on the link and you should be greeted with a prompt like the below:  

![Protocol Prompt](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/soey2u3ljb8aznib09k1.png)

Perfect. Click Open and our application should open as expected. 

![App Displaying our parameter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ykgvrn2amn6hezfqshs.png)

## Finishing Up
There we have it - its not a glamourous example but who said programming would be eh ? 

You can see the sample application here: 
{% github JamieMcManus/CustomProtocolAppExample%}

Got any improvements ? Then feel free to comment below !

And if you're feeling generous you can buy me a coffee with the link below ( and yes its all for coffee,  I drink a copious amount of it while writing ☕ )  


[![Buy Me A Coffee](https://cdn.buymeacoffee.com/buttons/default-black.png)](https://www.buymeacoffee.com/SUKaQp9)