Giter Site home page Giter Site logo

Comments (25)

leusbj avatar leusbj commented on May 25, 2024 2

@CZEMacLeod Yes, I have tried it. I have previously created (and never shared) a similarly purposed SDK project type, But I recently came across this one, and would rather contribute here, than maintain one myself.

Tapping into the SuggestedBindingRedirects ItemGroup is nice because it is populated as one of the outputs of the ResolveAssemblyReferences target ( found in Microsoft.Common.CurrentVersion.targets) when the build system examines the versions of the depenency items that were resolved via all the PackageReference and Reference... that's why my target conditionally runs only when there is a nonzero number of suggestions

The other benefit of placing the target that early in the build process is that

  • the changes are captured during a single build
  • simultaneous build/package/publish from an automated build pipeline /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:DeployOnBuild=true will capture the changed/working web.config

Let me know if you would like me to try creating a pull request incorporating that change

from msbuild.sdk.systemweb.

CZEMacLeod avatar CZEMacLeod commented on May 25, 2024 1

@gillg Looks like an interesting technique. I think there are a couple of issues though.
If it requires absolute paths (as @slang25 states) this would not work well.
When doing the initial compilation, the web.bindings.config file would not exist. This might result in errors due to a bad web.config file, and require you to compile again. In the case of a build server this wouldn't work well.

I think there might be some argument to keep the web.bindings.config file next to the web.config file, and keep it in source control. This would allow you to see if the actual config was changed, or if it was just assembly updates.

Can you confirm which versions of dotnet framework support this method - I couldn't find when it had been added in the MS docs.

The only other issue is that it requires manual intervention to add in the linkedConfiguration snippet. This could be done during the build process if it doesn't exist, I suppose, but then you are already updating two files, and they update every time.

The current target UpdateConfigWithBindingRedirects checks the hashes of the (potentially) modified config file including any new redirects, and only overwrites the original web.config if it differs. I think this is more efficient in general.
You are more than welcome to add your own target to your project file that behaves the way you describe, and not turn on OverwriteAppConfigWithBindingRedirects. If it works well, and doesn't suffer any of the issues previously described, feel free to post a link to an example repo, and we can look at adding it in; probably behind a different flag so you can choose which methodology to use.

To my mind though, the OverwriteAppConfigWithBindingRedirects feature basically makes up for the fact that you cannot double click the error message in the errors log like you can with a 'traditional' project, and leaves you with basically the same management tasks as you would have anyway. That way you don't have to learn a new method and any quirks that arise from it.

from msbuild.sdk.systemweb.

gillg avatar gillg commented on May 25, 2024 1

Oh !!!
Investigating deeper, the relative path is relative to bin folder !
So this is definitely working !

    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
	    <linkedConfiguration href="file://Web.bindings.config"/>
    </assemblyBinding>

So following @CZEMacLeod recomendations to version the file alongside Web.config si probably working with ../Web.bindings.config
But I'm not super fan to version this one and not other generated binding for library projects.

I just tested, and I don't have any warnings if I remove Web.binding.config before the build !
My guess is :

  • CSC make the build
  • AfterBuild target create the file
  • aspnet_compiler uses web.config and resolve the binding file.

EDIT: My bad @CZEMacLeod I think I just missed the warning ^^ So we always have the problem, but it seems not completely different than the current approach where we have to run the build two times no ?

Am I wrong ?

from msbuild.sdk.systemweb.

gillg avatar gillg commented on May 25, 2024 1

Thanks you a lot for all your details !
I will sleep on that and think if something matching all the needs could be done.

from msbuild.sdk.systemweb.

leusbj avatar leusbj commented on May 25, 2024 1

I think there might be a way to let MSBuild write the bindingredirects directly to the web.config file and do it early enough in the build process to not need to run the build twice.

It does still mean that for a source-controled code base, that bindingredirects are likely to be merged/checked in, but that is happening now for legacy web projects.

What if you were to do something like the following:

Sdk.props
Add a new property that lets people choose between doing nothing, proposing changes, and overwriting

  <!--
    ====================================================================================================

                                        GenerateBindingRedirects Behaviors
										
Traditionally (Microsoft.Common.CurrentVersion.targets) only does BindingRedirects for 
      Projects that are:
        Of OutputType == 'exe' or OutputType == 'winexe'
        Of TargetFrameworkIdentifier == '.NETFramework' and '$(TargetFrameworkVersion.TrimStart(vV))' >= '4.7.2'
      Additionally it chooses the filename of the config file to be updated as what exe projects want... 
        $(IntermediateOutputPath)$(TargetFileName).config -> the config file named after the assembly and in the IntermediateOutputPath
  
We are looking to attempt to facilitate the binding redirects generation for projects of this SDK type as well (regardless of Framework Version)
We are looking for the following default behavior (unless overriden inside the csproj)
      AutoGenerateBindingRedirects (true)
      GenerateBindingRedirectsOutputType(true)
      GeneratedBindingRedirectsAction (Overwrite) -> this will conditionally change wich config file is written to
    ====================================================================================================
  -->
  <PropertyGroup Label="Change the default BindingRedirects behavior for projects of this SDK type">
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
    <GeneratedBindingRedirectsAction>Overwrite</GeneratedBindingRedirectsAction>
  </PropertyGroup>

Sdk.targets
Replace the previously defined target "UpdateConfigWithBindingRedirects" with this new target

  <!--
    ====================================================================================================

                                        SystemWebProject_PreGenerateBindingRedirects
										
Inject this target between 
	ResolveAssmblyReferences (where the "@(SuggestedBindingRedirects)" itemgroup is populated... based on the logic that resolves assemblies being referenced
	and
	GenerateBindingRedirects (where the suggestedBindingRedirects are written to disk into a config file at $(_GenerateBindingRedirectsIntermediateAppConfig)
	
Then we can choose where the suggestedBindingRedirects are written, if at all (Default Value is Overwrite unless set by project)
    '$(GeneratedBindingRedirectsAction)' == '' -> Prints message giving options of what the developer can choose from
    '$(GeneratedBindingRedirectsAction)' == 'Propose' -> Creates new Web.Proposed.config file showing proposed changes... if Hierarchy/Nesting is correct, it will display underneath the web.config
    '$(GeneratedBindingRedirectsAction)' == 'Overwrite' -> Updates the $(AppConfig) aka web.config in the project root
    
    In general we want to emit a "warning" whenever we either do, or don't do something to help developers find the property that drives this behavior
    ====================================================================================================
  -->
  <Target Name="SystemWebProject_PreGenerateBindingRedirects" BeforeTargets="GenerateBindingRedirects"
	Condition="'$(AutoGenerateBindingRedirects)' == 'true' and '$(GenerateBindingRedirectsOutputType)' == 'true' and @(SuggestedBindingRedirects->Count()) > 0 ">
    <PropertyGroup Label="Set the location of the file to which the suggestedBindingRedirects should be written during the GenerateBindingRedirects Target">
      <_GenerateBindingRedirectsIntermediateAppConfig Condition="'$(GeneratedBindingRedirectsAction)' == 'Propose' " >Web.Proposed.config</_GenerateBindingRedirectsIntermediateAppConfig>
      <_GenerateBindingRedirectsIntermediateAppConfig Condition="'$(GeneratedBindingRedirectsAction)' == 'Overwrite' " >$(AppConfig)</_GenerateBindingRedirectsIntermediateAppConfig>
    </PropertyGroup>

    <Warning Condition="'$(GeneratedBindingRedirectsAction)' != 'Propose' and '$(GeneratedBindingRedirectsAction)' != 'Overwrite'"
	Text="Generated Binding Redirects have been applied only to the $(TargetFileName).config. You should incorporate them into the web.config. Consider setting &lt;GeneratedBindingRedirectsAction&gt;Propose&lt;/GeneratedBindingRedirectsAction&gt; to create a file containing the proposals. Consider setting &lt;GeneratedBindingRedirectsAction&gt;Overwrite&lt;/GeneratedBindingRedirectsAction&gt; to automatically update web.config with proposals."  />
    <Warning Condition="'$(GeneratedBindingRedirectsAction)' == 'Propose'"
	Text="Generated Binding Redirects have been applied only to the Web.Proposed.config. You should incorporate them into the web.config. Consider setting &lt;GeneratedBindingRedirectsAction&gt;Overwrite&lt;/GeneratedBindingRedirectsAction&gt; to automatically update web.config with proposals." />
    <Warning Condition="'$(GeneratedBindingRedirectsAction)' == 'Overwrite'"
	Text="Generated Binding Redirects have been applied automatically to the web.config. This warning will disappear on the next build." />

  </Target>

from msbuild.sdk.systemweb.

CZEMacLeod avatar CZEMacLeod commented on May 25, 2024 1

@julealgon In this case, the web.config file is part of the head project and is used from the root of the application, rather than being converted to xxx.exe.config beside the compiled file in the bin folder. As such it is not possible to 'hide' the bindings from the source code, as it won't compile if the bindings file does not exist (if you use the linked config mechanism).
In that case, you need a config file with the same top level xml element as the part of the config you are linking, so you would need to extract all the redirects under a single assemblyBinding root element for the link. That is not what the native mechanisms do, so you would need to create your own task using something like the XMLPeek and WriteLines or XMLPoke commands to 'patch' the file on build.
The existing Razor library uses some of that mechanism to do the Views/web.config files, although there is a PR #61 to use the built-in system for all cases as it prevents issues with formatting changing and a lot of git noise.
The file url is evaluated relative to the bin folder, so you would need to ensure that the url is consistent for that too.
The way that is it now implemented thanks to @leusbj is much cleaner and more robust in nearly all regards, (see the rest of this thread for reasons why) and I would recommend just using

<GeneratedBindingRedirectsAction>Overwrite</GeneratedBindingRedirectsAction>

as per the templates.
If you want to continue this, I suggest opening a discussion on alternative methods for handling bindings rather than continuing here in this closed issue.

from msbuild.sdk.systemweb.

gillg avatar gillg commented on May 25, 2024

P.S: I edited my previous description, in Web.config, and in case of linkedConfiguration it seems that the assemblyBinding node has to be outside <runtime>

from msbuild.sdk.systemweb.

slang25 avatar slang25 commented on May 25, 2024

In my testing (a very long time ago) I found that the path would be ignored if it's relative, and would only work if it's an absolute path.
Have you managed to get it working?

from msbuild.sdk.systemweb.

slang25 avatar slang25 commented on May 25, 2024

At my work we have a pretty gross convention of razor generating our web.config files, which has caused us all kinds of pain, but did allow for me to leverage this little known feature to get automatic binding redirects working well for us.
image
I remember trying for quite some time to solve this with relative paths and it never working, it's an undocumented behaviour and a real shame.

from msbuild.sdk.systemweb.

gillg avatar gillg commented on May 25, 2024

At my work we have a pretty gross convention of razor generating our web.config files, which has caused us all kinds of pain, but did allow for me to leverage this little known feature to get automatic binding redirects working well for us. I remember trying for quite some time to solve this with relative paths and it never working, it's an undocumented behaviour and a real shame.

Indeed the relative path seems fails silently... I didn't realize it ! I definitely don't understand how this feature can be usable without relative path !
Nevermind, I love your trick ! But I guess the code part is not directly in the Web.config ? It's part of your application?
There is no bad effect to include the whole dll config which contains the whole web.config (including linkedconfiguration) + bindings ?

from msbuild.sdk.systemweb.

slang25 avatar slang25 commented on May 25, 2024

Yeah, what I'm showing in that screenshot is useless to anyone else 😆 We happen to generate our web.config files as we deploy them, I cannot recommend anyone doing that.

But I do remember trying to solve this for the longest time, linkedConfiguration feature is essentially useless in it's current form.

from msbuild.sdk.systemweb.

gillg avatar gillg commented on May 25, 2024

To finish answering @CZEMacLeod XmlPeek seems exists since a long time : https://github.com/dotnet/msbuild/commits/main/src/Tasks/XmlPeek.cs like https://github.com/dotnet/msbuild/commits/main/src/Tasks/FileIO/WriteLinesToFile.cs
(they was already existing in 2015, during the first public git commit)

from msbuild.sdk.systemweb.

slang25 avatar slang25 commented on May 25, 2024

Ooooh, that's huge! I'll do some exploring on my side and see if we can remove some of the hacks we have.

from msbuild.sdk.systemweb.

gillg avatar gillg commented on May 25, 2024

To be discussed, but we could admit to add <NoWarn>MSB3276</NoWarn> by default to avoid errors and trust the automatic binding generation.

from msbuild.sdk.systemweb.

slang25 avatar slang25 commented on May 25, 2024

🤔 I haven't got it to work yet, the file I want to link is in the bin folder, but it's not taking effect. I'll keep testing

from msbuild.sdk.systemweb.

gillg avatar gillg commented on May 25, 2024

🤔 Except if it was another joke it should work. The compiler was happy... I will check again when I can.

from msbuild.sdk.systemweb.

CZEMacLeod avatar CZEMacLeod commented on May 25, 2024

@gillg The current approach requires running the build 2 times after a library/package update. (Or really just once to do the binding update). That code can then build on a build server without warnings and only needs building once, locally or remotely. Also, if you checkout the code, or perform a clean it compiles immediately without multiple compile steps. Your approach seems to always result in warnings that need supressing.

I wasn't referring to when the MSBuild tasks were added - It would be relatively trivial to add code and custom tasks if it couldn't be handled by MSBuild directly - I was referring to the assemblyBinding / linkedConfiguration elements in app/web.config.

You mention not checking in the auto-binding redirect files of libraries. I think the difference here is that a web application project is not really a library, but is the actual execution point for the project, even if it is a DLL not an EXE and is launched 'inside' of IIS.

There are a few other issues, with not having the config file as part of the project, when it comes to publishing etc.
Also, I believe that VS requires the correct bindings in place for when it edits razor pages, otherwise it cannot handle intellisense etc. (This might be an issue if you checkout or clean the code and the bindings config is deleted).

Right now, I'm not getting the vibe that this is any more robust, or user friendly, than the current approach, although it may work better for specific use cases.

I'll still consider a PR for a fully featured solution, but it should be completely generic, and require the absolute least amount of work from an end user to use. Having to go back to a project and remember how something worked, or get someone else up to speed with it, is always a pain point. Just now you can set the property and basically forget about it - you will get the warnings (and message telling you it is fixed and to recompile) if you do an update in the future and not have to worry.

I kind of feel right now that any logic and/or custom tasks required for this, would be better bundled up as a separate design-time nuget package - maybe something like MSBuild.SDK.SystemWeb.LinkedBindings. You could then install it if you wanted the binding redirects handled this way, or just use the SDK 'bare' and enable OverwriteAppConfigWithBindingRedirects if you want to do it that way. If there is anything specific that needs hooking or adjusting in the SDK to work this way, I'd be happy to oblige, and/or accept a PR for that.

from msbuild.sdk.systemweb.

CZEMacLeod avatar CZEMacLeod commented on May 25, 2024

I have just released a new package for razor class libraries.

As part of that package I

  1. Set the default of OverwriteAppConfigWithBindingRedirects to true instead of false. I'm not sure if I should also update the main package - I'm not sure if anyone is using this without the option at the moment.
  2. Added the XmlPeek/XmlPoke version to support updating any web.config files that are not in the root - e.g. with custom settings like in the Views folder.

Things I found out:

  1. The built-in mechanism that generates the binding redirects does some odd stuff with having multiple assemblyBinding elements.
  2. When using XmlPoke, it seems to mess up line endings (I think specifically in multi-line comments). It may also affect the whitespace for end tags in some cases.

This leads to -

  1. A warning about inconsistent line endings when opening the file in the editor.
  2. If you then check in the changes - you get a lot of other changes showing in git other than the bindings that have changed.

I am considering whether to move this functionality into its own package (as previously described) so that it could be shared between the two SDKs, and whether to write a custom task to do it in .NET rather than rely on the native MS Build tasks, and their foibles.

@gillg @slang25 If you have any further thoughts on this - especially as compared to using linkedConfiguration elements - I'd be interested to hear from you.

from msbuild.sdk.systemweb.

CZEMacLeod avatar CZEMacLeod commented on May 25, 2024

@leusbj Very interesting. I had not tried to force the output config file to overwrite the web.config file before. This looks like a very promising approach.
I will have to look under the bonnet of this process and see if it can be augmented further.
Have you actually tried this approach using the SDK? (I think just injecting your PropertyGroup and Target into the project file and ensuring that the built-in mechanism is turned off should do it?)
I wasn't aware of SuggestedBindingRedirects - I will have to look at that itemgroup in more depth too. Even without using the mechanism you are proposing, it would probably be faster to detect using this than the current mechanism using file hashes.

from msbuild.sdk.systemweb.

CZEMacLeod avatar CZEMacLeod commented on May 25, 2024

@leusbj I'm more than happy to take a PR from you including this feature.
I would suggest putting the props and targets in seperate files (similar to the new Razor SDK project has), and include them from the main SDK files.
I would suggest making all default values for props conditional on them not being set, so that any properties set globally in Directory.Build.props don't get overwritten.
I would also suggest changing Propose / web.Proposed.config to Preview / web.BindingRedirects.config (technically you could leave both in - I am more worried that someone will have a release type of Proposed so the file might conflict).
I think you also need to add the web.xxx.config file to the project and it automatically pulls in publish profiles and configurations as well as the root file, but won't include anything else by default.

<ItemGroup>
   <None Include="web.BindingRedirects.config" Condition="EXISTS('web.BindingRedirects.config')" />
</ItemGroup>

from msbuild.sdk.systemweb.

CZEMacLeod avatar CZEMacLeod commented on May 25, 2024

With the inclusion of the new binding redirects options, I'm going to close this issue.
I will probably need to incorporate the same features into the Razor SDK but that doesn't need to be done here.

from msbuild.sdk.systemweb.

stevenvolckaert avatar stevenvolckaert commented on May 25, 2024

I've noticed while updating to MSBuild.SDK.SystemWeb v4.0.79, the conditional include of Web.BindingRedirects.config, which lead me to this issue.

@CZEMacLeod I couldn't find the use of Web.BindingRedirects.config documented on the wiki, and I was wondering whether this new feature would allow one to have auto-generated binding redirects @ compile time (with overwrite of Web.BindingRedirects.config)?

from msbuild.sdk.systemweb.

CZEMacLeod avatar CZEMacLeod commented on May 25, 2024

@stevenvolckaert The documentation is a little behind I'm afraid - but the messages generated should direct you to the solution.
There is a new property GeneratedBindingRedirectsAction which controls the action.
If it is set to Overwrite it will directly update the bindings in web.config, overwriting the file directly on build.
If it is set to Preview, it will write the correct bindings to web.BindingRedirects.config where you can manually copy them to the live web.config file as required.

from msbuild.sdk.systemweb.

stevenvolckaert avatar stevenvolckaert commented on May 25, 2024

That's clear @CZEMacLeod, thank you for explaining.

from msbuild.sdk.systemweb.

julealgon avatar julealgon commented on May 25, 2024

Oh !!! Investigating deeper, the relative path is relative to bin folder ! So this is definitely working !

    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
	    <linkedConfiguration href="file://Web.bindings.config"/>
    </assemblyBinding>

@gillg I tried to use this setup while converting my project to SDK-style but couldn't make it work. Can you or @CZEMacLeod elaborate on how this is supposed to work?

First, there is no such Web.bindings.config file generated by the SDK (only a Web.BindingRedirects.config one). I tried changing the value there from "file://Web.bindings.config" to "file://Web.BindingRedirects.config" but it still doesn't have any effect.

I was hoping that this approach would keep the binding redirects "hidden" for the most part and always auto-generate them on build in a completely transparent manner (similar to how it works with other modern projects where there is no need to have a bindingRedirects section in the app.config file anymore).

Perhaps I'm missing something here, but I've also not seen this method documented in the Wiki.

For now, I've included the

<OverwriteAppConfigWithBindingRedirects>true</OverwriteAppConfigWithBindingRedirects>

Flag in my project but I'd ideally want to not have to have the binding redirects all explicit in my web.config file.

from msbuild.sdk.systemweb.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.