This is a migrated thread and some comments may be shown as answers.

Using Telerik Blazor component in a razor project

1 Answer 504 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Patrizia
Top achievements
Rank 1
Iron
Patrizia asked on 26 Apr 2021, 01:45 PM

     Dear all,

     we are oing to start a migration of our portal from Razor to Blazor server. Problems comes when i trie to take into telerik UI.

     As soon i did the basics steps explained here

                 https://docs.telerik.com/blazor-ui/getting-started/server-blazor

and here

                 https://docs.telerik.com/blazor-ui/knowledge-base/blazor-in-asp-net

But Kestrel server didnt' go up. It crasched on

app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute("default", "{controller}/{action=Index}/{id?}");

....

on

System.Reflection.ReflectionTypeLoadException: 'Unable to load one or more of the requested types.
Method 'BeginInvokeJS' in type 'Microsoft.AspNetCore.Components.WebAssembly.Services.DefaultWebAssemblyJSRuntime' from assembly 'Microsoft.AspNetCore.Components.WebAssembly, Version=3.2.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.'

 

 

Why it is seaching for 3.2.1.0 while i am in framework 5?

Regards

       Daniele

 

 

 

 

Marin Bratanov
Telerik team
commented on 26 Apr 2021, 04:15 PM

Hi Daniele,

This is just a guess, but this error indicates that a WebAssembly blazor project is being referenced in the MVC/RazorPages project you already have, while you need to have a Server-side Blazor project. 

At this point I can suggest you compare against the sample project we have in this repo to find the difference causing the problem: https://github.com/telerik/blazor-ui/tree/master/common/razor-components.

Regards,
Marin Bratanov
Progress Telerik

Тhe web is about to get a bit better! 

The Progress Hack-For-Good Challenge has started. Learn how to enter and make the web a worthier place: https://progress-worthyweb.devpost.com.

1 Answer, 1 is accepted

Sort by
0
Patrizia
Top achievements
Rank 1
Iron
answered on 27 Apr 2021, 09:35 AM

Hi Marin

I looked to you sample but is really simple compared to the huge quantity of things i have on the project.

But i'm super sure that i'm not having any web assembly project, all of them are razor projects.

Is there a way i can explicitelly ask for a blazor server?

Is There a way to post my files? I would like to show you how it is configured...

Regards

Daniele

BElow you can find my StartUp.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using dblu.Portale.Core.Infrastructure.Classes;
using dblu.Portale.Core.Infrastructure.Identity.Services;
using dblu.Portale.Core.Infrastructure.Interfaces;
using ExtCore.WebApplication;
using ExtCore.WebApplication.Extensions;
using FluentMigrator.Runner;
using FluentMigrator.Runner.Initialization;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Serialization;
using NLog;
using NLog.Extensions.Logging;
using NLog.Web;
using Syncfusion.Blazor;
using Syncfusion.Licensing;

namespace dblu.Portale
{
    /// <summary>
    /// Class that start up the web site
    ///     -> Boot strap the enviroiment
    ///     -> Load the external plugins
    ///     -> Manage the DB Migration
    /// </summary>
    public class Startup : IAssemblyProvider
    {
        /// <summary>
        /// Extension paths (in witch search for plugins, in addiction to local directory)
        /// </summary>
        private readonly string extensionsPath;

        /// <summary>
        /// Log of the System
        /// </summary>
        private readonly Logger _log = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="configuration"></param>
        /// <param name="hostingEnvironment"></param>
        public Startup(IConfiguration configuration, IWebHostEnvironment hostingEnvironment)
        {
            Configuration = configuration;
            HostEnvironment = hostingEnvironment;
            this.extensionsPath = hostingEnvironment.ContentRootPath + configuration["Extensions:Path"];
        }

        /// <summary>
        /// COnfiguration interface
        /// </summary>
        public IConfiguration Configuration { get; }

        /// <summary>
        /// Envroinment
        /// </summary>
        public IWebHostEnvironment HostEnvironment { get; }

        /// <summary>
        /// Configure the services
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            # region AUTHENTICATION
            services.Configure<CookiePolicyOptions>(options =>
            {              
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddAuthentication(options =>
            {
                options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            }).AddCookie(options => { options.LoginPath = "/Account/Login"; })
            .AddJwtBearer("Bearer",options => 
                    {
                        options.RequireHttpsMetadata = false;
                        options.SaveToken = true;
                        
                        options.TokenValidationParameters = new TokenValidationParameters()
                        {
                            ValidateIssuer = false,
                            ValidateAudience = false,
                            ValidAudience = "",
                            ValidIssuer = "",
                            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"].PadRight(32, '.')))
                        };
                        options.ForwardSignIn = "/Account/Login";
                    });

            #endregion

            #region RAZOR
            services.AddRazorPages(options =>
            {
                options.Conventions.AuthorizeFolder("/");
                options.Conventions.AllowAnonymousToPage("/Error");
                options.Conventions.AllowAnonymousToPage("/Account/Login");
                options.Conventions.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
            }).AddNewtonsoftJson();           
            #endregion

            #region MVC
            services.AddMvc().AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());//.AddNToastNotifyToastr();
            #endregion


            #region BLAZOR
            services.AddServerSideBlazor();
            #endregion


            #region MISC

            services.AddExtCore(this.extensionsPath,this);
            services.AddKendo();
            services.AddDistributedMemoryCache();
            services.AddHttpContextAccessor();
            services.AddSession(options => {
                options.Cookie.Name = "dbluPortaleCookie";
                options.IdleTimeout = TimeSpan.FromMinutes(30);
                options.Cookie.HttpOnly = true;
                options.Cookie.IsEssential = true;
            });
           
            services.Configure<IISServerOptions>(options =>
            {
                options.AutomaticAuthentication = false;
            });

            #endregion

            #region SERVICES

            services.AddTransient(typeof(IIndexManager), typeof(IndexManager));

            #endregion

            #if (DEBUG)
            var mvcviews = services.AddControllersWithViews();
                if (HostEnvironment.IsDevelopment())
            mvcviews.AddRazorRuntimeCompilation();
            #endif

            services.AddTelerikBlazor();
            services.AddSyncfusionBlazor();
        }

        /// <summary>
        /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            SyncfusionLicenseProvider.RegisterLicense("NDI1NDc5QDMxMzkyZTMxMmUzMEVtV2pXZU5JanFMdFAwZnZLcG9EZnNzNm5nSzYxeGN0U0ZYQ1pHcDFRd1E9");
    
            if (!env.IsProduction())
            {
                app.UseStaticFiles(new StaticFileOptions
                {
                    FileProvider = new PhysicalFileProvider(@$"C:\Users\{Environment.UserName}\.nuget\packages\syncfusion.blazor.core\19.1.0.57\staticwebassets"),
                    RequestPath = "/_content/Syncfusion.Blazor.Core"
                });
            }
            else app.UseStaticFiles();




            if (env.IsDevelopment())
                app.UseDeveloperExceptionPage();
            else
                app.UseExceptionHandler("/Error");
            app.UseSession();
            app.UseDefaultFiles();
          
            app.UseCookiePolicy();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseNToastNotify();
    
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute("default", "{controller}/{action=Index}/{id?}");
                endpoints.MapRazorPages();
                endpoints.MapBlazorHub();
               
                endpoints.MapFallbackToPage("/_Host");
            });

            app.UseExtCore();

            ApplyFluentMigrator();

        }

        /// <summary>
        /// Apply Fluent Migrator to the current database
        /// </summary>
        private void ApplyFluentMigrator()
        {
            try
            { 
            IServiceProvider ISP = new ServiceCollection().AddFluentMigratorCore().ConfigureRunner(rb => rb
                                                          .AddSqlServer()
                                                          .WithGlobalConnectionString(Configuration["ConnectionStrings:dblu.Access"])
                                                          .ScanIn(AppDomain.CurrentDomain.GetAssemblies().Where(y => y.GetName().Name.StartsWith("dblu.Portale")).ToArray()).For.Migrations())                                          
                                                          .Configure<RunnerOptions>(opt => { opt.Tags = new string[] { }; })
                                                          .BuildServiceProvider(false);
            using (var scope = ISP.CreateScope())
            {
                var runner = scope.ServiceProvider.GetRequiredService<IMigrationRunner>();
                if (runner.HasMigrationsToApplyUp())
                    {
                        _log.Warn($"Startup.ApplyFluentMigrator: Migration ...");
                        runner.MigrateUp();
                        _log.Warn($"Startup.ApplyFluentMigrator: Migration completed");
                    }
                _log.Info($"Startup.ApplyFluentMigrator: DB is up to date");
            }
            }catch(Exception)
            {
                _log.Warn($"Startup.ApplyFluentMigrator: No migrations found into assemblies");
            }
        }

        /// <summary>
        /// Load the plugin aseemblies (and their deps)
        /// </summary>
        /// <param name="path"></param>
        /// <param name="includingSubpaths"></param>
        /// <returns></returns>
        public IEnumerable<Assembly> GetAssemblies(string path, bool includingSubpaths)
        {
            _log.Info($"Startup.GetAssemblies: Loading lazy assemblies...");
            var pluginsPath = Path.Combine(path);
            string fullPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
        
            List<string> rootFiles = Directory.GetFiles(Path.GetDirectoryName(fullPath), "*.dll", SearchOption.TopDirectoryOnly).ToList();
            List<string> plugFiles = Directory.GetFiles(pluginsPath, "*.dll", SearchOption.TopDirectoryOnly).ToList();
            plugFiles.AddRange(rootFiles);

            List<Assembly> Loaded = new();
            List<Assembly> PlugIns = new ();
            List<Assembly> Identity = new ();

            List<Assembly> Asm = AppDomain.CurrentDomain.GetAssemblies().ToList();

            foreach (var assemblyFile in plugFiles)
            {
                //ATTENZIONE!Devo caricare tutti gli assembly, non posso limitarmi ai soli "dblu.portale.plugin"
                //altrimenti mancano le dll collegate.
                try
                {
                    if (Asm.FirstOrDefault(y => y.Location+y.GetName().Name == assemblyFile) == null)
                    {
                        Loaded.Add(AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyFile));
                        string AsmName = Path.GetFileName(assemblyFile).ToLowerInvariant();
                        if (AsmName.StartsWith("dblu.portale.plugin"))
                        {
                            PlugIns.Add(Loaded[^1]);
                            _log.Info($"Startup.GetAssemblies: Plug-in -> {Loaded[^1].GetName().Name} sucessefully loaded");
                        }
                        if (AsmName.StartsWith("dblu.portale.identity.") && !AsmName.Contains("usersmanagement"))
                        {
                            Identity.Add(Loaded[^1]);
                            _log.Trace($"Startup.GetAssemblies: Identity -> {Loaded[^1].GetName().Name} sucessefully loaded");
                        }
                        Asm.Add(Loaded[^1]);
                    }
                }
                catch (Exception) 
                {
                    _log.Warn($"Startup.GetAssemblies: Unable to load {assemblyFile} ");
                }
            }
            if (Identity.Count > 1)
                _log.Warn($"Startup.GetAssemblies: Loaded more than one Identity plugin ({Identity.Count})!");
            if (Identity.Count < 1)
                _log.Error($"Startup.GetAssemblies: Missing Identity plugin");
            else
                _log.Info($"Startup.GetAssemblies: Identity PlugIn -> {Identity[0].GetName().Name} sucessefully loaded");

            _log.Info($"Startup.GetAssemblies: Dinamically loaded {Loaded.Count}/{Asm.Count} assemblies...");
            _log.Info($"Startup.GetAssemblies: Loaded {PlugIns.Count} assemblies as external plugins");


            return Loaded;
        }

    }
}

 

 

 

 

Patrizia
Top achievements
Rank 1
Iron
commented on 27 Apr 2021, 11:22 AM

Let me add that this error happens as soon as i add the packages with nuget!
Patrizia
Top achievements
Rank 1
Iron
commented on 27 Apr 2021, 12:54 PM

Again on this.

I dig really in deep and i see that the problem is that we are loading all assemblies that we found in base folder for feed our plugin system..

Since your assembly reference to Mono.WebAssembly.Interop.dll , it generates that we load it and we have the error.

I tried to avoid to load it but still cannot move forward.

:-(

Regards

Daniele

 

Marin Bratanov
Telerik team
commented on 27 Apr 2021, 05:25 PM

Hello Daniele,

I see a couple of potential issues I can see here:

- the line endpoints.MapFallbackToPage("/_Host"); should not be necessary, adding Blazor components to an MVC/RazorPages solution should not need it because it won't use the blazor routing.

- loading all assemblies like that should not be needed, the framework can resolve the dependencies. I am not aware of any reasons to manually load assemblies for ASP.NET (Core) or Blazor, and I recommend you do not do that.

I would suggest you start off by plugging in a vanilla Blazor app (or, rather, components) in a rather plain MVC/RazorPages setup so you can see how that works at its core, so you can then repeat the process in your real app. Then, you can start adding references to complex components and third party vendors.

As for the interop dll - I am not aware of issues with that in the general setup. Nevertheless, our next (2.24.0) release will carry optimizations around the dependencies we bring. We will stop carrying Newtonsoft.Json, Microsoft.AspNetCore.Components.WebAssembly and Microsoft.AspNetCore.Components.WebAssembly.DevServer.

--Marin

 

Tags
General Discussions
Asked by
Patrizia
Top achievements
Rank 1
Iron
Answers by
Patrizia
Top achievements
Rank 1
Iron
Share this question
or