The Official Blazor Thread



  • End of the month, this thing is coming out with core 3.

    What is it? A new web framework that looks a lot like modern asp.net razor stuff. But it's a lot more interesting than that: the interweaving of c# and html is now componentized to the level of popular web frameworks like angular, and more importantly what it really is is a web assembly framework. It loads actual .net dlls, and while it supports direct js interop, what you're essentially getting is a client or server side (its a switch) development for web that doesn't require any js at all.

    I've only messed with it a little, but it's GOOD. It's extremely simple, too. It's both simpler than angular and asp.net. I think we have a winner here.



  • @Magus said in The Official Blazor Thread:

    simpler than angular

    This. So much this. As anyone who's ever tried to debug Angular templates knows, it's a real horror that's totally impenetrable to anybody without a strong background in compiler theory. Heck, I have a strong background in compiler theory and even then I can just barely make out what's going on!

    Blazor templates get preprocessed into very straightforward imperative C# code that gets saved to the obj folder in your project. The code does exactly what it looks like it's doing in building a DOM tree, and it's right there for you to inspect if anything goes wrong. It's just night and day, the difference between Blazor and Angular.



  • @Magus already had a look at this previously and am now waiting for the official release.



  • @Magus Okay, I'm currently looking at this. I have one specific task in mind and, as a newbie, am currently not quite sure how to go about it, considering that previous iterations had a strict separation of server and client.

    Now, what I'd like is to have (besides the magic Signal-R routes) some simple CRUD routes which receive some parameters and then output, say, plain text as a response.
    Where do I define this in the Startup.cs file? All the examples I could find were severely outdated.

    public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddRazorPages();
                services.AddServerSideBlazor();
                services.AddSingleton<WeatherForecastService>();
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Error");
                    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                    app.UseHsts();
                }
    
                app.UseHttpsRedirection();
                app.UseStaticFiles();
    
                app.UseRouting();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapBlazorHub();
                    endpoints.MapFallbackToPage("/_Host");
                });
            }
        }
    


  • @Rhywden I'm not sure what you're going for. Blazor is meant to be a front end application framework, so you'd use something like an asp.net webapi project as your backend, and either blazor server-side or webassembly as a separate application.

    The main thing is that while serverside blazor is on a server and can do applicationy things in theory, that isn't what its for.



  • @Magus Then I can't use it because this application does need some basic routing for an OAuth-like communication scheme to authenticate clients. I.e. API endpoints which do not serve up the whole shebang.



  • @Rhywden So then you need a backend server either way. So build a backend server, and use Blazor to make the frontend that talks to it.



  • @Rhywden there's a guide somewhere for doing Auth stuff with it, I found it when searching before.



  • @Mason_Wheeler Erm, this is the "server-client" Blazor setup?



  • @Magus Yeah, I found that as well. That's only for authentication against the server itself, though. And the other examples use some kind of nuget plugins for Google and the like.



  • @Rhywden server side just means that the processing of the ui elements and stuff is done on the server, and you have access to all of .net core 3. It's still a client app, like an angular app would be. You can theoretically do more stuff with the full framework and serverside rendering, but it's more expensive to host, and you're still expected to be connected to an actual back end.



  • @Magus I still don't see what's so difficult about this or so completely outlandish?

    I just need a route which does not serve up everything save for some kind of text-based output based on the POST-body. Unless you're telling me that by "server" you don't really mean "server".



  • @Rhywden There is no POST body. That's a server thing. Blazor is a client-side SPA framework.



  • @Mason_Wheeler said in The Official Blazor Thread:

    @Rhywden There is no POST body. That's a server thing. Blazor is a client-side SPA framework.

    Backed by a server if you configure it to be thus.



  • @Rhywden Yes, but the server interactions are explicit.

    Instead of building a form and SUBMITting it via standard HTML, you use an onsubmit handler which will take the data and use a HttpClient to POST it to the server, then you await the result and handle the data.



  • @Mason_Wheeler So you're telling me that when they say "blazor-server" it's actually a big fat lie. Nice.



  • @Rhywden I'm not touching server-side Blazor with a ten foot pole. The entire concept is a big mass of :wtf:. I'm talking about how this works on proper client-side Blazor.

    I would imagine that on server-side Blazor, it would look pretty much the same, except that the onsubmit event handler is executing on the server so you don't need to POST the data to it; you just process the data (probably asynchronously) and then respond to the result.



  • @Mason_Wheeler said in The Official Blazor Thread:

    @Rhywden I'm not touching server-side Blazor with a ten foot pole. The entire concept is a big mass of :wtf:.

    Then I'm not sure why you're talking to me when I'm currently all about processing stuff on the server?

    Yeah, I'll go back to Node. At least the whole client-server architecture makes sense there. And it's easier to figure out who renders what.



  • @Rhywden said in The Official Blazor Thread:

    Then I'm not sure why you're talking to me when I'm currently all about processing stuff on the server?

    Because processing stuff on the server is completely orthogonal to your choice of client-side framework?

    Yeah, I'll go back to Node. At least the whole client-server architecture makes sense there. And it's easier to figure out who renders what.

    :eek: Nothing about Node makes sense, starting from its very existence!



  • @Mason_Wheeler said in The Official Blazor Thread:

    @Rhywden said in The Official Blazor Thread:

    Then I'm not sure why you're talking to me when I'm currently all about processing stuff on the server?

    Because processing stuff on the server is completely orthogonal to your choice of client-side framework?

    What?

    f80ad790-f44b-4fb2-bb35-c1dcc8a39121-image.png

    Pardon me if I understood the word "server" to actually mean "server".



  • @Rhywden ...yeah. That's server-side Blazor.

    Blazor is a frontend framework. Always has been. But somewhere along the line, someone got the brillant idea of making it execute on the server, generating the DOM and processing events server-side instead of locally, and sending DOM updates to your browser over a websocket connection. Virtually everyone looked at that and went :wtf_owl: at the time, but they did it anyway, and Somebody Important At Microsoft decided that this should actually be the first priority!

    If you're actually using SSB, you can do validation "locally" because your "local" context is the server, not the browser. But I'd recommend against using it.

    Either way, you need a server to do authentication, and a frontend to drive it, and the two are quite orthogonal to one another.



  • @Mason_Wheeler Okay, then back to Node it is. At least there a server is a server and I can finely control who gets to render what in an easily understood manner.



  • @Rhywden or use the "Blazor WebAssembly App", where the client is the client and the server is the server and you don't have to deal with :trwtf: that is Node.



  • @Rhywden I've explained it to you twice now, so here's a third: blazor is front end. Front. End. Serverside blazor is front end. It is not back end. It still isn't back end. No, while you read that sentence, it still hasn't become back end.

    Webassembly is hard, so while they work to get the version that you host on a dumb file server and the client does all the work up to the quality level they want, they made a version that is much more backward compatible, because they do all the ui on the server and just send the html, much like asp.net always has. This communicates with the part they send to your browser purely through signalr.

    If you need back end stuff, it has to be separate. There is no possible world where blazor could possibly mean anything in the back end, because it is entirely designed around messing with html. The separation is absolute.

    You may be able to hack your client app to do back end stuff, because the entire framework is there, but dont act like this is confusing. Node has confused things for people by mixing things up,;this is a much simpler, complete detachment.



  • @Magus Wait, so you just said that "they do all the ui on the server". That's called SSR and is very much something a server does (after all, it's in the name). The only difference here is that they're able to serve up fragments instead of whole pages and that it's done through SignalR instead of HTTP.

    I'm not sure that I am the one who mixes up the terminology here.

    By the way, I now have found others who wanted to do the same thing and, surprise, because it actually is an ASP.net server you're running you can do just what I want.



  • @Mason_Wheeler said in The Official Blazor Thread:

    @Rhywden ...yeah. That's server-side Blazor.

    Blazor is a frontend framework. Always has been. But somewhere along the line, someone got the brillant idea of making it execute on the server, generating the DOM and processing events server-side instead of locally, and sending DOM updates to your browser over a websocket connection. Virtually everyone looked at that and went :wtf_owl: at the time, but they did it anyway, and Somebody Important At Microsoft decided that this should actually be the first priority!

    If you're actually using SSB, you can do validation "locally" because your "local" context is the server, not the browser. But I'd recommend against using it.

    Either way, you need a server to do authentication, and a frontend to drive it, and the two are quite orthogonal to one another.

    wat. So you can have an app interacting with a backend, and the app lives on your server and the backend lives on your server(or elsewhere I guess) and just pretends to do network stuff between frontend and backend, and pretends not to do network stuff between the client and the frontend(that is now on the server?).

    You're like one step away from a webpage that just opens an RDP to a traditional app.



  • @AyGeePlus I know! It's such a brillant system!



  • @AyGeePlus said in The Official Blazor Thread:

    You're like one step away from a webpage that just opens an RDP to a traditional app.

    That's pretty much how serverside Blazor works. If the Internet drops, it stops responding and covers the page with "attempting to reconnect". I'm not sure who'd want to make a website like that other than local services maybe.

    IMO Blazor was obviously meant to be client-side and the whole serverside thingie was added when someone realized it was relatively simple to make since it's just run the same code on the server and send the results through.

    (Also, there do exist webpages that just open an RDP to a traditional app.)



  • @AyGeePlus the goal was to drop the entire framework into webassembly, and have it be entirely clientside. Because that's hard, they did a quick, bad version that acts more like asp.net, but with built in signalr to keep the ui responsive.

    Serverside blazor is a stopgap, and while you can do more with it than with the webassembly version because of it, it's recommended that you don't treat it any differently.



  • @Magus said in The Official Blazor Thread:

    Serverside blazor is front end. It is not back end

    Serverside blazor runs on the server, and while it might not be how it was intended, you could theoretically connect to a database right in the same code that renders the page and do all the stuff that would normally be "backend" there.

    The only issue I see is that you'd have one connection per client. But you can probably instantiate a single "backend" class to handle that stuff. And then you'll have N instances of frontend code talking to one (or a few) instances of the backend code, as you would expect, but without the need for HTTP connections or even serializing data in between.



  • @Magus So, get the entire .NET ecosystem into webassembly and just... run it inside every browser?

    I have no idea how to evaluate this. Either it's genius or it's stupid, but it's certainly not mediocre, whatever happens.



  • @anonymous234 said in The Official Blazor Thread:

    And then you'll have N instances of frontend code talking to one (or a few) instances of the backend code, as you would expect, but without the need for managing your own HTTP connections or even explicitly serializing data in between.

    FTFY. That stuff's all still there; it's just hidden from you under the hood.



  • @AyGeePlus I lean toward genius as a .net dev who despises Javascript. This essentially brings us the dream that was silverlight without the mocking resulting from a browser plugin. But yeah, webassembly bootstraps the framework, which is a variant of mono since that's now the preferred portable version, and then it runs compiled dlls. They have the framework under 2mb so far, with more to go and advanced tree shaking planned for .net 5.





  • @AyGeePlus said in The Official Blazor Thread:

    @Magus So, get the entire .NET ecosystem into webassembly and just... run it inside every browser?

    Not "the entire ecosystem"; just the parts your project needs. There's a linker in there that does a lot of work to keep downloads down, and they're constantly iterating on it.



  • @Mason_Wheeler To send the rendered result to the client, yes. The rest of the logic however (what would normally be frontend->backend requests) would run as local function calls.



  • @Magus said in The Official Blazor Thread:

    as a .net dev who despises Javascript

    I wish they'd split Blazor into two project: one that let you run arbitrary C# code and .NET assemblies in the browser, and one that used that to implement their template system and all that stuff.

    I want people to be able to write <script type="c#"></script> and manipulate the DOM from there without having to learn all that stuff.



  • @anonymous234 you can just make it js and have it call c# methods if you want I'm pretty sure.


  • Considered Harmful

    Server-side Blazor smells too much like WebForms to me.



  • This post is deleted!


  • So, a component receives parameters. The component draws itself using those parameters however it wants. That's intuitive.

    And components are themselves classes. So, to make something like a tab control, in an ideal framework, I'd expect to be able to implement a TabControl component that receives a bunch of Tab components, and then renders the actual tabs and the body of the active tab. Something like

    <TabSet>
        <Tab Title="First tab">
            <h4>Greetings from the first tab!</h4>
        </Tab>
        <Tab Title="Second tab">
            <h4>The second tab says Hello World!</h4>
        </Tab>
    </TabSet>
    

    But here's the problem: it's currently impossible for TabSet to receive or access those Tab components in code like that.

    Components can receive child content parameters with syntax like that, but only one for each parameter name (or or a single one with the implicit name ChildContent), and most importantly only of type RenderFragment.

    Instead, how you're expected to do it is

    1. Parent renders the big block containing all the child components.
    2. Child components render to nothing, receive a reference to the parent, and call the parent to give it a reference to themselves.
    3. Parent selectively calls children to receive their content and render it.

    (See Microsoft TabSet example, DevExpress training samples)

    Am I an inflexible curmudgeon looking for reasons to complain, or is that a stupid annoying workaround for the lack of a simple feature? Couldn't TabSet could simply receive those Tab instances in a [Parameter] public IEnumerable<Tab>?

    And don't think just tabs, think of something like <Page> receiving <Header><Body><Sidebar><Footer> or a <Table> receiving <Row>s.

    It worries me that Microsoft most likely considers the current approach to be better, given that ASP.NET Core does everything in the most roundabout way possible.



  • @Magus Can't you just use Blazor for the views in a MVC project?



  • So anyway, I asked myself "can you make animations with just this"? And the answer is yes, yes you can.

    @page "/Kitty"
    @inject IJSRuntime JSRuntime
    @implements IDisposable
    @{
        double bigAngle = getAngle(1);
        int imageCenterX = 500 + (int)(400 * Math.Sin(bigAngle));
        int imageCenterY = 500 - (int)(400 * Math.Cos(bigAngle));
    }
    <h1>KITTEH!</h1>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" style="background-color:lightgray; max-height:500px /*I don't know CSS, shut up*/">
        <image width="200" height="200" x="@(imageCenterX - 100)" y="@(imageCenterY - 100)"
               transform="rotate(@((int)(getAngle(-2) * 360 / Tau)),@imageCenterX,@imageCenterY)"
               href="@imgUrl" />
    </svg>
    
    <script suppress-error="BL9992">
        /*Blazor devs have decreed that we can't have script tags because idiots try to modify them at runtime (see https://github.com/aspnet/Blazor/issues/552)
         but you can bypass the error with that attribute*/
        var instance;
        function startAnimation(i) {
            instance = i;
            requestAnimationFrame(animationFrameJS);
        }
        function animationFrameJS(timestamp) {
            instance.invokeMethodAsync('AnimationFrame', timestamp).then(
                function (shouldContinue) {
                if (shouldContinue) {
                    requestAnimationFrame(animationFrameJS);
                } else console.log("Got signal to stop calling");},
                function () { console.log("invokeAsync failed");/*this never actually gets called*/ }
            );
        }
    </script>
    @code{
        const string imgUrl = "https://placekitten.com/100/100";
        const double Tau = 2 * Math.PI;
        double getAngle(double turnsPerSecond) => (turnsPerSecond * timestamp.TotalSeconds * Tau) % Tau;
        string toStr(double d) => d.ToString(System.Globalization.CultureInfo.InvariantCulture);
        DotNetObjectReference<Kitty> referenceToSelf;
        bool finished = false;
    
        TimeSpan timestamp;//could have been a double but might as well do it right
    
        override protected void OnAfterRender(bool firstRender)
        {
            //we have to make a proxy object to pass to javascript, to refer to this 
            //even though the SignalR connection obviously already knows what instance it's talking to 
            //and we probably should dispose of it when navigating away 
            referenceToSelf = DotNetObjectReference.Create(this);
            if (firstRender) JSRuntime.InvokeAsync<int>("startAnimation", referenceToSelf);
        }
        [JSInvokable]
        public bool AnimationFrame(double milliseconds)
        {
            //even disposing referenceToSelf won't stop the JS loop so we have to do it ourselves
            if (finished) return false;
            timestamp = TimeSpan.FromMilliseconds(milliseconds);
            StateHasChanged();
            return true;
        }
    
        public void Dispose()
        {
            referenceToSelf?.Dispose();
            finished = true;
        }
    }
    

    And it runs smoothly too. As long as the frames are not travelling over the internet.



  • @anonymous234 said in The Official Blazor Thread:

    Blazor devs have decreed that we can't have script tags because idiots try to modify them at runtime (see https://github.com/aspnet/Blazor/issues/552) but you can bypass the error with that attribute

    The Right Way To Do This â„¢ is to put the script tag in your base HTML page, rather than inside a Razor template. The problem isn't "idiots modifying them at runtime", but rather the Blazor framework itself "modifying" it by unloading and reloading the DOM fragment of this Razor template when you navigate to something else in the SPA and then back to this. That will end up causing unexpected behavior.



  • @Mason_Wheeler said in The Official Blazor Thread:

    is to put the script tag in your base HTML page, rather than inside a Razor template

    Yes but now I have to modify thing B just to implement thing A which is entirely unrelated to B. And that's bad. They could easily have given us a @javascript{ } keyword or something to handle it.



  • @anonymous234 I don't agree. Thing A being contained within thing B means that they aren't "entirely unrelated" at all; there's a very logical and consistent relationship there.



  • @magnusmaster you can use razor syntax?


  • ♿ (Parody)

    @Mason_Wheeler said in The Official Blazor Thread:

    @anonymous234 said in The Official Blazor Thread:

    Blazor devs have decreed that we can't have script tags because idiots try to modify them at runtime (see https://github.com/aspnet/Blazor/issues/552) but you can bypass the error with that attribute

    The Right Way To Do This â„¢ is to put the script tag in your base HTML page, rather than inside a Razor template. The problem isn't "idiots modifying them at runtime", but rather the Blazor framework itself "modifying" it by unloading and reloading the DOM fragment of this Razor template when you navigate to something else in the SPA and then back to this. That will end up causing unexpected behavior.

    Wasn't the whole point of this that you could use C# and not have to use javascript?!



  • @boomzilla Yes. However, not all of the browser's API is available to WASM yet, so some level of JS interop remains necessary for certain tasks, for the moment at least.



  • @Magus Razor is almost useless because it only does server-side rendering. I assume Blazor can do what Razor does but client-side so I can write MVC views without having to spend time writing Javascript to handle state manually.