Adding asp.net controllers/views from a Class Library - c#

I am building a class library in C# with .NET 6 (possibly 7) for use with ASP.NET Core sites.
I would like this class library to (among other things), contain a configuration UI (kinda like how Swashbuckle builds up an OpenAPI UI - I checked out the source code and couldn't quite wrap my mind around that portion).
I figured creating controllers/views in the class library would be the way to go.
The controllers are working automatically (although, I'm mildly concerned about routing conflicts -- what if I have a /foo/bar route in my class library and the project using this library also has a /foo/bar route?).
The views, however, do not seem to be added automatically. I've tried embedding and following the folder conventions, but I still get the error:
An unhandled exception occurred while processing the request.
InvalidOperationException: The view 'Index' was not found. The
following locations were searched: /Views/Foo/Index.cshtml
/Views/Shared/Index.cshtml
Here's the relevant portion of the class library:
What do I have to do to get these Views loaded/parsed/working from a class library? (Or is there a better alternative to doing what I'm trying to do without Views?)

ApplicationParts is the answer, but I found the documentation a little hard to follow, so here's what I did:
var assembly = typeof(FooController).Assembly;
#this.AddControllersWithViews()
.AddApplicationPart(assembly)
.AddRazorRuntimeCompilation();
#this.Configure<MvcRazorRuntimeCompilationOptions>(options =>
{ options.FileProviders.Add(new EmbeddedFileProvider(assembly)); });
The key for me was .AddRazorRuntimeCompilation(); and the following line to add a file provider.

Related

Share classes vs. swagger generated classes

I have an asp.net/Blazor VS solution with three projects,
Shared
asp.net core apis
Blazor webassembly.
I created bunch of classes in Shared project and from the other two projects, made a reference to the Shared project. All is good so far.
Then I used Swagger UI to generated stubs for me so I can interact with the remote APIs. Swagger UI created the Service.cs and Contract.cs which is great. The problem is that Contract.cs has redefined the classes that I have declared in Shared projects under it's own namespace. Now I don't know which to use and which to import. If I use my own Shared classes, then I won't be able to use the APIs from swagger in Service.cs without casting. If I modify Contract.cs, then all my changes will be lost the next time I run Swagger UI.
This also resulted in having two DBContext - 1) the one I defined and 2) The one that swagger defined. Now every time I want to do something, I also have to use --context parameter on the command line to specify which DBContext to use.
The question is how can I use my own classes yet use swagger to make life easy in terms of talking to the remote APIs? What is the best practice here?
When you want to use Swagger (client side) then you shouldn't reference the Shared project. The swagger claases is what you get/want then.
But you don't need Swagger in Blazor. The opportunity to share DTO classes in Shared is one of the highlights of Blazor.
If you want some help with the boilerplate stuff on the Client then there are options like refit. See this blog about it.

Nancy Modules are globally discovered, how to implement the same idea with .net?

I have a web api project, and I have a HttpSelfHost server.
I know that when using NancyFX you can use Nancy.Self.Host to host a server and then make calls to the API which extends NancyModule, I got 2 questions.
How does Nancy see the api module if its in a different project?
How do I implement the same idea without Nancy?
the idea is:
having an API project, and having a server project, how could I run the server, and then send requests with the API routes?
any help\tip would be appreciated!
NancyFX can do that discovering all the assemblies in his working directory and looking for class who extend NancyModule through reflection. NancyFX use an IoC container to collect the modules.
I suggest you to check NancyFXcode on github especially the boostrapper and the Nancy Boostrapper who use TinyIoC as IoC container.
EDIT:
Looking that code you should be able to replicate the feature you need.
It can be you need less infrastructure to load classes dynamically.
I suggest you to look at System.Reflection namespace. With that you can load assemblies dynamically and search the classes implementing a known interface or they have a known prefix.

How exactly does Microsoft.Extensions.Configuration dependent on ASP.NET Core?

Does ASP.NET Core implement IConfiguration access to config values?
Most likely my question arose because I don't understand what exactly ASP.NET Core is. Well, I know it's a web framework, Not sure, but looks like it is a namespace in .NET, or a package... I know in php, a framework could be a set of classes (a namespace) or compiled library which is provided as an extension so I presume a similar approach in .NET.
Initially, I didn't intend to wrap my head around ASP.NET Core yet. I needed to store some config for my simple console C# application (VS Code and .NET Core). I've found a lot of topics (for example here: How to read values from config.json in Console Application) that to read JSON (recommended) config. Given that, I added three necessary nugget packages:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.FileExtensions;
using Microsoft.Extensions.Configuration.Json;
I need to use:
new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json").Build();
This returns an object that implements the IConfigurationRoot/IConfiguration interface. But all the examples are given in an ASP.NET Core context. I have a really simple app and I don't need any of ASP.NET functionality yet.
So I've tried to access IConfigurationRoot without ASP.NET. The resulting object stores values from config file, but does not have all methods of its interface to access them.
How to explain this in context of .NET namespaces? Does ASP.NET Core implement methods to access values from IConfiguration like Get<T>()?
If Microsoft.Extensions.Configuration is part of or heavily dependent on Microsoft.AspNetCore.App, why is it in different namespace?
If I add ASP.NET Core (NuGet package and namespaces), will it be an overkill?
Maybe I should use soemthing other than ConfigurationBuilder to read JSON?
Microsoft.Extensions.Configuration, like other packages in the Microsoft.Extensions namespace (e.g. Options, or DependencyInjection), are packages that were created as part of the ASP.NET Core framework. The way ASP.NET Core and all its related packages were built however is in a very modular way, so all the libraries can be used within the ASP.NET Core context, or without.
You have to understand those packages just as libraries. They are included in ASP.NET Core since the framework builds on top of them, but if you do not need the ASP.NET Core web framework, you can still use those libraries separately without any mention of ASP.NET Core. That’s actually why they live inside the Microsoft.Extensions namespace instead of Microsoft.AspNetCore: They are completely separate projects. Of course, development of those packages is done by the ASP.NET Core team and the design decisions of ASP.NET Core do affect how those extension packages evolve; but the team is very careful with these packages so that the general use is not affected.
So that all being said, how do you use these packages? Just like any other library, you just add a NuGet reference to it. Since Microsoft.Extensions.Configuration is the base library which does not come with any facility to load files, you also need Microsoft.Extensions.Configuration.Json if you want to load JSON files.
But then it’s really straight forward:
var configuration = new ConfigurationBuilder()
.AddJsonFile("config.json")
.Build();
// retrieve configuration values
Console.WriteLine(configuration["foo"]); // bar
Console.WriteLine(configuration["baz:bar"]); // qux
For this example, the config.json looked like this:
{
"foo": "bar",
"baz": {
"bar": "qux"
}
}
So you can just load the configuration like this. Be sure to still check the documentation though. It may be about the configuration used inside of ASP.NET Core but the underlying concepts still apply (e.g. how configuration paths look like, or how binding works).
Finally, note that this is really just meant for configuration. Loading data from JSON is just one of many configuration sources you can with Microsoft.Extensions.Configuration. But regardless of what provider you will use, you will end up with the same configuration format that has the concepts of sections and key paths.
If you came to the package while looking how to parse JSON, then it’s likely that you are looking at the wrong tool. If you want to parse JSON to retrieve a proper data structure, like you would use when using JSON as a way to serialize data, then you should look at something different. The most common solution for parsing JSON (serializing too) is using Json.NET which is a very powerful and flexible tool to deal with any kind of JSON data.

ASP.NET Core 2.0: resource namespace not visible

I'm trying to make an ASP.NET Core 2.0 application multi-language. I created a resource file under a folder "Resources" called "Resource.it.resx". I set its access modifier to Public and its Namespace to Resources.
After (re)building the solution I cannot see this namespace in the C# code now in the cshtml code.
Is there some other steps to do?
There are two things you need to take into account:
Only a Resource.resx generates a namespace, culture-specific resources such as Resource.it.resx does not generate a namespace. This is the intended behavior.
ASP.NET Core's localization practices suggest not to use resources directly, but rather find the localized strings using IStringLocalizer.
I suggest you to read the fundamentals of ASP.NET Core localization in the official MSDN guide. There you will find examples for localizing strings in Controllers, Views and wherever you need them.
First thing check if your resource namespace is visible in controller,
like Resources.Resource.
I had not and in this situation I have created emtpy resource class, ex. my resources name is ServiceResources.en-US.resx, in same folder I have ServiceResources.cs empty class too.
Check if you have imported your namespace in _ViewImports.cshtml correctly, with IStringLocalizer class.

Can a class be removed by code

I have a query whether there is any sensible (pinch of salt needed here) mechanism to 'remove' a class from my codebase.
I'm not trying to delete a .cs file here, I'm trying to kind of 'null out' a class.
I'm looking for something which does something along the lines of 'un-declaring' a class definition.
The reason for this slightly odd request idea is that I have a PCL with some shared entities. These entities are used by SQLite and in the PCL library I've defined the SQLite [PrimaryKeyAttribute] property so that I can mark the entities PKs.
In my consuming library I have SQLite for Windows Runtime installed and 'sqlite-net' for the linq like wrapper. It's in this wrapper that the [PrimaryKeyAttribute] is defined.
What I was hoping to do was define the [PrimaryKeyAttribute] class as below in the PCL library:
namespace SQLite
{
[AttributeUsage(AttributeTargets.Property)]
public class PrimaryKeyAttribute : Attribute
{
}
}
But the problem with that is that it's overwritten by the same definition in the consuming library. Things work happily if I comment out the attribute from the definition in the consuming library, but as soon as I (or someone else) updates the sqlite-net package we're going to hit a load of issues as the data access will fall over.
I suppose I'm looking for a kind of 'do not compile' flag of some form which I can apply to code in a different file. Any ideas/thoughts on this one?

Categories