
The ability to reuse code without duplication is always the aim of any developer following the DRY principle, Don’t Repeat Yourself.
Normally as developers we turn these things into a nugget package and install the library that way allowing us to reuse the code. This is great in a lot of circumstances but not always.
We can do that using compilation links within the csproj file to configure a project to compile files from a different project, well specifically a different path.
<ItemGroup>
<Compile Include="../Shared/Functions/Function1.cs" />
</ItemGroup>
The above snippet is how to include a file from another location to be compiled within our application.
My use case
Recently I have been working with a development team building an API for a service that will have both and Web UI and a Mobile App calling the API. Due to the two different client types we have implemented two different authentication options for the API which is being provided using policy in APIM. One is app to app, and one is a B2C route for the end users of the mobile app. This has been working great, until we got a requirement for both the web and the mobile app to use the same endpoint of the API. Due to the way the policy works this cannot be implemented without duplicating the endpoint within the same API.
To do this we chose to split the API into two projects that can then have their own APIM policies enforcing different authentication schemes.
//File: Functions.B2C.csproj
<ItemGroup>
<Compile Include="../Functions/SendEmailFunction.cs" Link="Functions\SendEmailFunction.cs />
</ItemGroup
In the above example you can see that within our new B2C function, we are including a function from the original Function App.
Link Property
The additional property added ‘Link’ allows us to set the symbolic link location for how it displays within Visual Studio. This is not required but is preferred for cleanliness when you are looking at the project within an IDE.
As you can see above the project within Visual Studio now shows our function, even though from a different project, and it’s clearly identifiable as a link from the icon.
Final implementation
The final implementation that we settled on was to even further split this out, ending up with the following projects:
- Functions.common
- Contains all of the shared code for the functions including the actual function definitions
- Functions.API
- Has no direct code, using compile links to include a subset of functions
- Function a
- Function b
- Function c
- Has no direct code, using compile links to include a subset of functions
- Functions.B2C
- Has no direct code, using compile links to include a subset of functions
- Function c
- Function d
- Function e
- Has no direct code, using compile links to include a subset of functions
As you can see we are now able to share functions between the two hosting applications without the need to duplicate actual code.
Conclusion
Developers should always aim to create DRY solutions where at all possible. This functionality helps with creating this especially in more speciliased or specific use cases which are not suited to creating an installable package. Packages are great for instances when the code will be shared to other solutions but in a case were the code is being used within the same solution this often creates more complication than is really required.
Above we have been able to create a shared set of functions and then deploy two different Function Apps using their own specified subset of the functions creating two individual APIs without having to repeat ourselves.