Thanks so much for this article! I found it after days of trying to wrangle a similar setup with current ASP.NET/Identity .NET 8, and with it I was able to get 90% of the way there.
And thanks to @Jovica I was able to fix the last remaining piece to get the auth+authz portion (roles) working by adding that last options.DefaultAuthenticateScheme
options.DefaultAuthenticateScheme
Thank you for mentioning the logs! Hours later Im up and running.
@Richard Algeni Jr And what was it you did up to this point to solve it?
Even in 2024 - working on an old project in VS 2008 - this also made my day! Thanks 😃
Thanks, mate, it was hard to find the answer to this question and only your guide includes all the required steps and details to avoid this redundant zooming.
@kapsiR - good catch. Might be useful to add that as another optional parameter to the helper.
EnableBuffering has an overload to specify the memory buffer size. Would prefer that over using a file baked buffer if the size and RPS fit.
Thank you, I was wondering why my local development server was serving my app to Firefox just fine. But as soon as I tried to access it through chrome, I was rejected with the chrome error and always landed on the HTTPS protocol.
Note: Before my current project, I was playing around with TLS encryption and certificates on a dev-server on the same port, that's probably how my chrome instance was “poisoned” with the HSTS header 😠. Greetings from Germany!
Funny thing is, I have the exact opposite problem (with CoreWCF): need to move namespace declarations down to individual message elements.
Outstanding. I missed the WebSurge part as i was speed reading the first time. Nice. You have quite a few goodies. I'm glad I've found this.
I also found your github before I found your site. The things I've discovered: my ignorance 😉
if you have a moment, would you please explain serving pages with images? I appear to have gotten far enough to make great progress on a project using your server. WOW.
I've come to something i've not been able to handle and have to go to work. Ive served a page with an image. set a breakpoint in your server MapFallback call and it's the image.
i suspect my ignorance is showing.
it's most likely, the <img src="./images/1537317.jpg" alt="This is a picture of produce" width="1024" height="150">
<img src="./images/1537317.jpg" alt="This is a picture of produce" width="1024" height="150">
i have tried using "http://127.0.0.1:5003/images/1537317.jpg"
does anyone have a suggestion?
Regards, D.
although I didn't see it documented (wt -h), this works: wt -d <folder> or wt --startingDirectory <folder>
wt -d <folder>
wt --startingDirectory <folder>
Finding this post was like finding water after two days RUNNING in the desert. Thank you so much for sharing!
You are a supreme being. This has been killing me for weeks! The secret sauce is in the 'Update' override.
Great content, thanks for this.
I tried the maximum-scale approach, but if I zoom in on another page and then go to my page that gets the viewport set to maximum-scale=1 it still gets the zoom from the previous page.
maximum-scale=1
I do have minimum-scale=1 set and that does work if the page had been zoomed out it will force the new page to be the right scale on load.
minimum-scale=1
I don't think you'd be able to compile a desktop application via AOT.
But to be fair haven't tried it. If never had apps that I could have used AOT on work with it - only thing it ever works for is overly simplistic stuff that's truly self-contained and has few or no outside dependencies.
Nice article, Rick!
Regarding the "Caveat: Requires the ASP.NET Runtime". Doesn't compiling the server app with AOT solve (or alleviate) this problem?
Thanks; this error is giving me a neck pain since yesterday - just trying to close a child window from its parent control and override the default close with the "x" button.
Thank you for this article. I have been reading a lot of pages regarding this topic. But this is the best so far, the actualy made my understand every part of the flow. Good work.
You helped me enormously. Thanks.
Running this gave me this error:
Add-BindingRedirect : Loading this assembly would produce a different grant set from other instances. (Exception from HRESULT: 0x80131401) At line:1 char:20 Get-Project -all | Add-BindingRedirect CategoryInfo : NotSpecified: (:) [Add-BindingRedirect], FileLoadException FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PackageManagement.PowerShellCmdlets.AddBindingRedirectCommand
To solve this:
I was facing the same issue when attempting to run this command, but managed to run it by creating the DWORD variable LoaderOptimization with 1 for value under the key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework, then restarting Visual Studio and running the command in the Package Manager Console again. source: https://stackoverflow.com/questions/76049195/add-bindingredirect-loading-this-assembly-would-produce-a-different-grant-set
Hi All,
I have already added following safe with * but still I'm not able to clone the repo using groovy script, error remains same
[safe] directory = *
stdout: stderr: fatal: not in a git directory
I hate these kinds of errors. WebView2 is probably spinning its own threads and one of them probably fails. Hopefully your solution solves the problem. You probably tried everything but I have a few recommendation that might help:
procmon
This is a big problem for me when I either have multiple controls or the user opens up a second instance of the app. When the error occurs, my app disappears without warning. I agree with all that you wrote above.
@Martin - the issue is that the app is not reliably unloading or not unloading quickly enough perhaps. Yes it should work with just appoffline.html, but the reality is that it doesn't and so files are locked in the folder and can't be updated. Shadow copy works around that by putting things in a new folder and also managing the staggered execution letting the existing IIS AppDomain run out requests that might still be running, while getting the new AppDomain with the updated files to start up.
appoffline.html
I wonder why this doesn't work with Filesystem deploy... it should be faily simple mechanic to add the app_offline and then proceed to copy files after waiting for x milliseconds.
How can I find the .gitconfig file in a linux distro? I am using openSUSE for a work from an undergraduate course and git config --global --add safe.directory <Git folder> just doesn't work...
git config --global --add safe.directory <Git folder>
thank you!
Just putting this here: https://gist.github.com/OysteinAmundsen/9e6b2ebdf8264ec0e25a0540661949bc
It is made for angular, but the point is:
pointerover
focus
pointerout
blur
This works if you do not want to or cannot change font-size, and do not want to or should not prevent users from zooming in the application. Zoom is only disabled when input field is in focus.
Hmmm... I think the sdk key is used for picking the SDK version used for executing dotnet CLI commands, not for the runtime used to execute the application.
sdk
Should be easy to test - allowPreRelease plus rollforward should also allow using the preview release. I think I tried that at the time. I'll take another look when I get back to my machine.
allowPreRelease
You can set allowPrerelease in global.json like so:
allowPrerelease
global.json
{ "sdk": { "allowPrerelease": false, "rollForward": "latestMajor", "version": "7.0.401" } }
I personally also use the above settings and have found them to provide less friction.
@Sam (does @ work here?) calls to await Task.Delay(0) will generally be more responsive. You pay the overhead of creating a system timer, but Task.Yield indefinitely surrenders control to the scheduler. I was recently benchmarking a background-thread audio-capture loop in a program rendering OpenGL frames on the main thread, and Delay reliably returned about 10% faster than Yield (3600 FPS vs 3250 FPS). Non-Task options were even better, but obviously have no applicability here.
await Task.Delay(0)
Task.Yield
As for ConfigureAwait most of what you read about .NET (Core) is really about ASP.NET, because Microsoft has gone almost completely web-blind. ASP.NET Core doesn't need it, but whether it is required elsewhere is still a question of the framework you're using.
ConfigureAwait
Have you checked out the new alternative ?
Directory.GetCurrentDirectory()
.NET Framework has built-in PNG compression, but (for speed) uses the video driver for PNG decompression.
PNG compression (whether done by .NET or other libraries) correctly uses unsigned bytes for some of the measurements.
Some video drivers incorrectly parse the value as a signed byte, which causes out-of-memory errors.
Example:
Here's how I dead with unexpected long text. I cap the height, but let the user override and see all the text. Warning: Little JS to make it work.
https://codepen.io/edddy/pen/GRPRJmE
In my app it's styled better, but you'll get the idea
@Mikhail - You don't really need a callback, you can implement it yourself once you've made it past the EnsureCore2WebViewAsync() call. You can set an initialization flag and fire an event/action to allow notification.
EnsureCore2WebViewAsync()
In fact, I created a wrapper component called WebViewHandler that deals with this in a Westwind.WebView component. It wraps a lot of this non-sense with some additional flags and events. That can help, but ultimately you still have to wait for the control to be ready.
WebViewHandler
We software developers are herd animals.
The mad rush to "Async Everywhere" reminds me of the Y2K problem. Y2K arose from the faulty notion taught for years that responsible programmers should cleverly use just 2 digits to represent a year instead of 4, thereby saving 2 precious bytes. The herd failed to comprehend that in the future (today), bytes would abundant and free.
Today, the herd is saying "Async Everywhere" to make everything more responsive. But processing power is becoming cheaper and faster anyway. The motto should be "Async Where It's Needed".
The decision by the WebView2 creators to go "Async Everywhere" was shortsighted. The cost in unnecessary complexity far outweighs any benefits.
Rich Strahl you said it well: I can't help but think that a lot of this pain could have been avoided if the developers of the WebView2 would have just provided the ability to call into the DOM synchronously. There's nothing inherently async about DOM access. There's no IO you're waiting on and DOM interactions calling into code tend to be universally fast. What's slow is not the DOM code calls, but DOM UI updates, which happen in the background, separately anyway. In short, there's no realistic reason that DOM access should have to be async.
You need to add <UseWpf>true</UseWpf> and target net70-windows I believe since these are features out of the WPF namespaces.
<UseWpf>true</UseWpf>
net70-windows
Hey, Rick. It's Rick here too. 😃
Thanks for the code, I've been using it for a while. But now I'm writing a .NET 7 project and System.Windows.Threading is not available. Do you know if someone wrote a version of this to .NET (Core)?
Thank you!
This post helped me, thanks. I have a partial view that resolves fine in one place in my controller. The action name does not match the view name. It works just fine, it resolves the partial view. However, a few lines down in another action method, it is unable to resolve the exact same view. I can't figure out any difference. However in the 2nd case I resorted to using the FULL path, plus the extension, and the view is resolved. Very odd.
Thanks! Evan
@Rick 17 yrs later this page was still helpfull.
Listen, as old as this article wants to be, it has been a huge help in sorting out some modern issues. Thanks, Rick - super post. Although for some reason the remove namespace wouldn't solve the issue. I had take a different approach - don't add the namespace to the general web.config file but instead add it to the web.config file for the local folder where the modules that needed it lived.
Thanks much. This is the only thing I have found that consistently works.
Thank you very much for this article. I am working on an IdentityServer solution where the IS will call an endpoint in my MVC application to ensure the client. So, I had to combine OpenId/Cookie and Bearer. Your solution helped me out. I had to set the DefaultChallengeScheme to OpenId.
builder.Services.AddAuthentication( options => { options.DefaultScheme = customAuthenticationSchemeName; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme,
This article was SO helpful. Thank you so much for putting this together. I used a slight variation of your method to inject global JavaScript variables into static pages that are uploaded to a file share by content creators which are then served up through my app via a NAS mount. The content creators just have to add my marker comment where they want my script block injected and then I provide token data that their accompanying JavaScript leverages to authenticate to REST APIs. The session data is captured via another middleware that enforces OAuth OIDC code flow authentication when requesting static "index.html" files. It's actually a really beautiful combination, but not quite as complex as your need.
I always seem find great gems of yours when I'm trying to solve my most difficult coding problems so thank you again.
Have you ever tried using the Await() extensions provided by Prism.Core throught Brian Lagunas some time ago. Seems a good solution for me, to run async code inside of synchronous code, but with the little disadvantage that you have a callback chain if you want to run multiple calls after each other.
@Jason - This is a desktop app, so it's not using global DI and I don't see a need to set that up.
I wanted to be able to log both to Application Insights but also keep a local log for users to be able to share their logs if they report issues - otherwise it's really difficult to correlate.
Rick - thank you for your blog -- I always find it well thought out and informative.
I'm curious why you chose to use a telemetry client rather than Application Insights provider for ILogger?
I ask because we have .Net 6 application that runs as Windows Service on roughly 1000 clients and growing and we log to Application Insight using the ILogging provider. Recently we noticed that some clients stop logging mysteriously even though the Event Log provider continues to function. Researching this issue led me to your blog post.
Any thoughts about the issue are greatly appreciated.
Jason
not sure if it's an update but the maximum scale trick doesn't work on iphone. The only thing that works is setting the font-size to anything greater than 16px (16px doesn't work either it has to be greater).
Interestingly, when I initialise a local git repo using vscode built-in tooling, and then try and use gitextensions to view or check-in I get the same problem. It's down to a number of files in the .git folder having some strange owner that's not even an accessible user on my local machine (windows 11 pro, no domain, local account only). Fix is the same, and I prefer to own my files - allthough executables, hooks and anything else I didn't create myself get deleted!
This problem seems to appear on some machines and not others for unknown reasons. We do all our builds with Linux, but it seems to fail more often when using WSL2 (windows subsystem for Linux).
We have this code (Yocto/Openembedded): def define_iv(d): import subprocess source_dir = d.getVar('OEROOT',True) cmd = "git describe" proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, cwd=source_dir) out, err = proc.communicate() return out.decode("utf-8").rstrip()
And it sometimes will return "" instead of the hash if we don't do the "git config --global --add safe.directory ...".
"git describe" for a git repository source will be done many many times during a build. But it will only fail once in a blue moon, which makes me think that git must have bugs.
Started working for me only after I've added the DefaultAuthenticateScheme
DefaultAuthenticateScheme
.AddAuthentication(options => { options.DefaultAuthenticateScheme = "JWT_OR_COOKIE"; options.DefaultScheme = "JWT_OR_COOKIE"; options.DefaultChallengeScheme = "JWT_OR_COOKIE"; })