RazorPage .NET 5 how to customize localization provider (.resx to database) - localization

I am in the process of migrating an ASP.NET Webform .net 4.8 to RazorPage .Net5.
In my asp.net webform website, I had deported the translation part to the database instead of a .resx file.
I had inherited from the following classes: ResourceProviderFactory, IResourceProvider and ExpressionBuilder
<expressionBuilders>
<remove expressionPrefix="Resources" />
<!-- For Translator -->
<add expressionPrefix="Resources" type="WebCore.Resource.SqlExpressionBuilder" />
</expressionBuilders>
<globalization uiCulture="auto" culture="auto" resourceProviderFactoryType="WebCore.Resource.SqlProviderFactory" />
which allowed to keep the asp.net syntax
<meta name="description" content="<%= GetLocalResourceObject("MetaDescription") %>" />
With razop pages you have to use
#inject IViewLocalizer Localizer
#Localizer["MyDescription"]
And configure service
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages().AddViewLocalization();
}
How to change the default behavior of the localization service, from which class should you inherit and how to inject this new class so that the resources are loaded with this new DB provider?

I implemented the solution, here's how.
Create classes that implement IStringLocalizer and IStringLocalizerFactory
In the Startup of the site
Add :
services.AddRazorPages().AddViewLocalization();
services.AddSingleton<IStringLocalizerFactory, SqlStringLocalizerFactory>();
into razor page use
#using Microsoft.AspNetCore.Mvc.Localization
#inject IViewLocalizer Localizer
<h1>#Localizer["Title"]</h1>
if you want to get the values in your c # code you can inject an IStringLocalizer but if your resource is in html you must use IHtmlLocalizer

Related

Standalone Blazor app as a Razor Class Library

Is it possible technically to have a full webassembly Blazor application as a Razor Class Library and then consume it in another ASP.NET project regardless of the consumer be MVC, Razor Pages, or Blazor app? Is it possible to define the routing within the Razor Class library?
I'm working on a project that is going to be published as a Nuget package. This package should be used in a variety of ASP.NET projects which are implemented as MVC, Razor Pages, or even Blazor.
I figured out how to get it running. I am using .NET 5.0.
First create a new Solution with a Razor Class Library project (Check the checkbox Support pages and views).
And create a MVC project.
In Startups.csadd the following:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddRazorPages();
services.AddServerSideBlazor();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapRazorPages();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Also make sure you have app.UseStaticFiles(); in your Configure method.
Then, in your Razor Class Library, you can copy and paste the Pages, Shared folders and all other razor files from the example Blazor webassembly project. Also don't forget the wwwroot css folder and add your own wwwroot folder to your RCL.
In the Pages folder also create a new cshtml file. This will be the entry point to your Blazor app.
Example code:
#page
#using PROJECTNAME
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Blazor WebAssembly Prerendered</title>
<base href="~/" />
<link href="/_content/PROJECTID/css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="/_content/PROJECTID/css/app.css" rel="stylesheet" />
#*https://learn.microsoft.com/de-de/aspnet/core/blazor/components/css-isolation?view=aspnetcore-5.0#razor-class-library-rcl-support*#
<link href="/_content/PROJECTID/PROJECTNAME.bundle.scp.css" rel="stylesheet" />
</head>
<body>
<app>
<component type="typeof(App)" render-mode="ServerPrerendered" />
</app>
</body>
</html>
<script src="_framework/blazor.server.js"></script> <!--blazor.webassembly.js didn't work-->
The important parts are the <base href="~/" /> and the _framework/blazor.server.js.
If you don't map this page to be at the root, like #page "/" you have to make sure all the static content is mapped to the project-id correctly.
Also make sure the paths in the example projects NavMenu.razor are correct if you don't use / as the root. Has to be correct in the Razor Components too.
If you have problems with the _Imports.razor file, try adding the NuGet package Microsoft.AspNetCore.Components.WebAssembly
Also add the correct namespace for your shared folder, in the example project it's PROJECTNAME.Shared. Change it accordingly.
Here's a blogpost that helped me get things the right way: https://blog.joelving.dk/2020/02/reusable-ui-and-interchangable-hosting-models-in-blazor/

Is it possible to use ASP.NET Core 2.x MVC on .NET Framework 4.6.1 console application

I'm attempting to port an ASP.NET MVC 4.x application over to ASP.NET Core 2.2. WebApi works great, but I'm stuck with porting over the MVC views. I've created a full "minimally viable" repro to show what I mean. The Program.cs looks like this:
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace TestApp
{
public class Program
{
static void Main(string[] args)
{
string port = "9005";
var host = new WebHostBuilder()
.UseKestrel()
.UseStartup<Startup>()
.UseUrls($"http://0.0.0.0:{port}")
.Build();
host.Run();
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvcCore()
.AddRazorViewEngine()
.AddJsonFormatters();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvcWithDefaultRoute();
}
}
}
I have one controller in Controllers\HomeController.cs that looks like this:
using Microsoft.AspNetCore.Mvc;
namespace TestApp.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
}
I have one view at Views\Home\Index.cshtml that looks like this:
#{
var x = "Test";
}
Home page
When I run the program, I can confirm I hit the breakpoint at return View(); - I get no exceptions or anything. However, the browser will return an error 500 and nothing is displayed.
My theory is I'm missing whatever the mechanism is that compiles the Index.cshtml into something the ASP.NET Core MVC framework can find. I've done a bit of research but it's very unclear how all this works. There is something called Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation which apparently does runtime compilation of cshtml files, but it has a .NET Core dependency. In the ASP.NET 4.x world, I believe there was an ASP.NET compiler that would run as a build target that handled this sort of thing, but it's a bit unclear how it works. Pretty much every Visual Studio template for ASP.NET Core is built around .NET Core, which seems to magically make this stuff work but I'm not exactly sure how. Anyone know what the next steps would be to get this to work? Thanks!
PS: The reason I cannot run on the .NET Core framework is because this project has a massive amount of dependencies on legacy .NET Framework (Windows) code which would take years to port over.
Edit: Here's my entire CSPROJ file (I've tried a few SDKs to no avail)
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net461</TargetFramework>
<OutputPath>bin\$(Configuration)\</OutputPath>
<DebugType>portable</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Formatters.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Net.Http" />
</ItemGroup>
</Project>
When your project targes .NET Framework you should install Microsoft.AspNetCore.Mvc.Razor.ViewCompilation package.
It contains build-time references required to enable Razor view compilation.
Include its package reference to your .csproj file:
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Version="2.2.0" PrivateAssets="All" />
This extra step is only aplicable on .net core project targets
Execute the below command at the project root to prepare the app for a framework-dependent deployment:
dotnet publish -c Release

Using MvcSiteMapProvider with exising StaticSiteMapProvider class

I'm converting as webforms app to MVC. The previous programmer built a class that inherits the StaticSiteMapProvider class to create his sitemap. He then placed this control on the page
<asp:SiteMapDataSource ID="sitemapSQLMenuProvider" runat="server" ShowStartingNode="False" />
and initialized it like this
Dim oSqlSiteMapProvider As New SQL.SiteMap.Provider.SQLSiteMapProvider(Session("KPISystemUserID"), PagePath)
oSqlSiteMapProvider.Initialize("MySiteMap", Nothing)
SiteMapDataSource1.Provider = oSqlSiteMapProvider.
He then used the menu control and specified the data source
<asp:Menu ID="menuMaster" runat="server" DataSourceID="sitemapSQLMenuProvider"/>
I created a class in my MVC project and copied the code over to create the SQLSiteMapProvider class. It created nodes... subnodes.. etc. Is there an easy way with the MvcSiteMapProvider package from Nuget to simply specify this class as where to get the Nodes from? All the documentation just keeps trying to get you to use a static XML file (which i can't use because our menus come from the DB).
It looks like the webform programmer set up his provider like this in the web.config
<siteMap defaultProvider="KPIMap" enabled="false">
<providers>
<clear />
<add name="KPIMap" type="System.Web.XmlSiteMapProvider" siteMapFile="~/System/MY.sitemap" />
</providers>
</siteMap>
and that xml file was simply
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="" title="" description="">
<siteMapNode url="" title="" description="" />
<siteMapNode url="" title="" description="" />
</siteMapNode>
</siteMap>
You'd think they would have added a simple way to plug in the name of a StaticSiteMapProvider class and be done with it.

Error:Type 'ASP._Page_views_index_cshtml' does not inherit from 'System.Web.UI.Page'

I had Asp.net web forms app, I want to convert it to responsive and to use Angularjs instead of web forms.
I started by adding two razor partial views:
views/login/login.cshtml
views/index.cshtml
Both views are pure html, except for rendering css/js
I also added to the routing:
routes.MapWebPageRoute("Login", "mobile/login", "~/views/login/login.cshtml");
routes.MapPageRoute("mobile", "mobile", "~/views/index.cshtml");
Now, when navigating to mobile/login will render with no problem, but navigating to mobile will give me the following error:
Type 'ASP._Page_views_index_cshtml' does not inherit from 'System.Web.UI.Page'.
I tried adding to index.cshtml the following:
#inherits System.Web.Mvc.WebViewPage
But got the same error!
Note: I don't have <system.web.webPages.razor> or <sectionGroup name="system.web.webPages.razor"> in my web.config
Any ideas?
Try to add the following to the web.config file in the (Views) folder:
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>

Spring.NET Validation Framework setup with ASP.NET MVC

I'm starting a new project for work, and I decided I want to give MVC a shot. It's a small internal site for a commute challenge.
I want to use Spring.NET for Validation. I have used Spring.NET before in Web Forms, but with no code behind as in traditional ASP.NET, how do I use the Page Validation framework Spring.NET provides?
Edit 1:
In an attempt to try this myself, here is what I have:
Web.Config
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/>
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
</sectionGroup>
</configSections>
<appSettings>
<add key="RouteValidator" value="RouteValidator"/>
<add key="UserValidator" value="UserValidator"/>
</appSettings>
<spring>
<context>
<resource uri="config://spring/objects"/>
<resource uri="~/Config/Spring.Web.cfg.xml" />
<resource uri="~/Config/Spring.Validation.cfg.xml" />
</context>
<parsers>
<parser type="Spring.Validation.Config.ValidationNamespaceParser, Spring.Core" />
</parsers>
</spring>
<system.web>
<httpModules>
<add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web" />
</httpModules>
</system.web>
</configuration>
Spring.Web.Cfg.xml
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">
<description>
Foo MVC Controller declarations.
</description>
<object id="HomeController" type="Foo.MVC.Web.Controllers.HomeController, Foo.MVC.Web"></object>
<object id="AccountController" type="Foo.MVC.Web.Controllers.RouteController, Foo.MVC.Web"></object>
<object id="RouteController" type="Foo.MVC.Web.Controllers.RouteController, Foo.MVC.Web"></object>
<object id="Spring.Web.UI.Controls.ValidationError" abstract="true">
<property name="Renderer">
<object type="Spring.Web.UI.Validation.IconValidationErrorsRenderer, Spring.Web">
<property name="IconSrc" value="validation-error.gif"/>
</object>
</property>
</object>
<object id="Spring.Web.UI.Controls.ValidationSummary" abstract="true">
<property name="Renderer">
<object type="Spring.Web.UI.Validation.DivValidationErrorsRenderer, Spring.Web">
<property name="CssClass" value="validationError"/>
</object>
</property>
</object>
<object id="standardPage" abstract="true">
<property name="MasterPageFile" value="~/Views/Shared/Site.master"/>
<property name="CssRoot" value="~/Content/"/>
<property name="ImagesRoot" value="~/Content"/>
</object>
</objects>
My validation file is very standard and basically a copy and paste from another project, therefore I didn't include it.
Now the problem I have is how do I use it? How do I get application context? My web forms project users Spring.Web.UI.Page, but I'm worried because the default pages in MVC derive from System.Web.Mvc.ViewPage, so that isn't going to work.
Or am I just not able to use Spring.NET's framework for MVC quite yet?
Thanks!
Thanks for any assistance.
You definitely can use Spring with ASP.Net MVC. You need to register that you are using it in the Global.ascx class then the framework will create Controllers based on what you have defined in your config file.
public class MvcApplication : System.Web.HttpApplication
{
...Routes stuff...
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));
RegisterRoutes(RouteTable.Routes);
}
}
public class ControllerFactory : IControllerFactory
{
public IController CreateController(RequestContext requestContext, string controllerName)
{
return IoC.Resolve<IController>(controllerName);
}
public void ReleaseController(IController controller)
{
//This is a sample implementation
//If pooling is used write code to return the object to pool
if (controller is IDisposable)
{
(controller as IDisposable).Dispose();
}
controller = null;
}
}
public static class IoC
{
static readonly IObjectFactory Factory
= new XmlObjectFactory(new FileSystemResource
(HttpContext.Current.Server.MapPath("~/Config/Spring.config")));
public static T Resolve<T>(string name)
{
return (T)Factory.GetObject(name);
}
}
Just make sure that the path to your spring config file is correct! This was adapted from this link.
On a wider note, this approach does not allow you to Spring the page classes, and being an MVC architecture, where views are pretty dumb classes, does not really support rich validation in the view itself in the manner you suggest. Look at either including the validation in the Model (post-back) in JQuery.
In best of my knowledge, the Spring Validation is not supported up to the latest release of ASP.NET MVC (1.0) and Spring.NET framework (1.3).
As far as incorporating Spring.NET with MVC, you can use MvcContrib project and come to the same code-base as posted by Colin Desmond (but you don't have to do the dirty work yourself).

Resources