Entity Framework Core - Customise Scaffolding - c#

In Entity Framework 6 we can add the T4 templates the scaffolding uses by running
Install-Package EntityFramework.CodeTemplates.CSharp
But in Entity Framework Core the scaffolding system does not appear to use T4 templates, nor does it seem like the scaffolding can be customised. It seems to be all in c# classes eg.
https://github.com/aspnet/EntityFramework/blob/a508f37cf5a0246e9b92d05429153c3d817ad5ec/src/Microsoft.EntityFrameworkCore.Tools.Core/Scaffolding/Internal/EntityTypeWriter.cs
Is there any way to customise the output from the scaffold?

There is a special, yet-to-be-documented hook to override design-time services:
class Startup
{
public static void ConfigureDesignTimeServices(IServiceCollection services)
=> services.AddSingleton<EntityTypeWriter, MyEntityTypeWriter>();
}
Then implement your custom generator.
class MyEntityTypeWriter : EntityTypeWriter
{
public EntityTypeWriter(CSharpUtilities cSharpUtilities)
: base(cSharpUtilities)
{
}
// TODO: Override with custom implementation
}
Update: See Yehuda Goldenberg's answer for another way to do this in EF Core 1.0.2+.

In .Net Core 1.1, the way to override design-time services is to implement the IDesignTimeServices interface in the startup assembly. For example:
public class MyDesignTimeServices : IDesignTimeServices
{
public void ConfigureDesignTimeServices(IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<EntityTypeWriter, MyEntityTypeWriter>();
serviceCollection.AddSingleton<DbContextWriter, MybContextWriter>();
}
}
See https://github.com/aspnet/EntityFramework/issues/5617

Related

Get link/API path in .NET 6

I have create a program that using .NET Framework 4.7.2 and I want to convert to .NET 6 (just for training purpose or future use.
The way when I get the link like "/jsonAPI/prxy001" in .NET 4.7.2 like this :
log.EndPoint = HttpContext.Current.Request.Url.AbsolutePath.ToString();
log.Endpoint is just a model
And I try to use it in .NET 6 said that "Current" is not available in HttpContext. I think the way or reference is defference. Can you tell me how?
P.S =
I generate that not in controller, but in another helper class.
Inject HttpContextAccessor in the startup configureservices method like below
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
then inject it via constructor in any class you need
public class Test
{
private IHttpContextAccessor context;
public Test(IHttpContextAccessor ctx) {
this.context = ctx;
}
}

How to add DbContext In Startup.cs without using Entity Framework?

I am currently working on a project where I am developing a class library that later on will be uploaded as a nugget package, such that if a user creates a.NET Core application, she/he can download the nugget package and use it accordingly.
Essentially within the class library, Entity Framework, Nethereum and other packages are installed as dependencies. One of my goals is not to require users to add Entity Framework to their application (since the nugget package (, i.e. the class library I am building)) already has it installed. For that reason, there is a DbContext that accepts the database connection string in the class library and builds the options.
public class BEFDbContext: DbContext
{
public BEFDbContext(string connectionString) :
base(SqlServerDbContextOptionsExtensions.UseSqlServer(new DbContextOptionsBuilder(), connectionString).Options) { }
public DbSet<ApplicationEvent> Events { get; set; }
}
Next, the user has to create another class in the application code that extends the BEFDbContext class found in the class library.
public class NewDatabaseContext: BEFDbContext
{
public NewDatabaseContext(string connectionString):base(connectionString){}
}
So far so good, however, at this point, I would like to 'initialise' the NewDatabaseContext class in the Startup.cs class. Generally, one would use Entity Framework and would add the code as such:
services.AddDbContextPool<NewDatabaseContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("defaultconnection"));
});
However, as I mentioned before One of the goals is to not require users/developers to add Entity Framework to the application (once again since we have it in the class library).
So, my question is How I can add the NewDatabaseContext class as DbCcontext in the Startup.cs without using Entity Framework?
Since you wanted the alternative response you can use Extension methods
in your library add the following code
public static class ServiceCollectionExtensions
{
public IServiceCollection AddApplicationDbContext<T>(this IServiceCollection services, IConfiguration configuration) where T : BEFDbContext
{
services.AddDbContextPool<T>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("defaultconnection"));
});
return services;
}
}
then in the startup of application you can use
public void ConfigureServices(IServiceCollection services)
{
...
services.AddApplicationDbContext<NewDatabaseContext>(Configuration);
...
}
You can have variations of this as per your need. Like accepting the connection string instead of the whole Configuration, etc.
This answer uses generics and extension methods. If you want more details then please checkout:
Generic methods: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-methods
Extension Methods: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

AbpDbContext and IdentityDbContext

I have an ASP.NET Core (v. 2.2) application that uses IdentityDbContext<User, Role, string>.
I'm adding Abp Framework to the application, I want to use AbpDbContext.
How to combine the functionality of two contexts?
You need to create a module class like below
public class BlogModule : AbpModule
{
}
and add your other module dependency in the attribute. Something like this
[DependsOn(typeof(BlogModule))]
public class WebAppModule : AbpModule
{
}
And read https://docs.abp.io/en/abp/latest/Module-Development-Basics

.Net Core with .Net Framework Configuration

How to set the Configuration Manager AppSetting into legacy .Net Framework dependency.
The WebApi in .Net Core but for the data access have to use the legacy .Net Framework. Then Base library structure is
public class OracleRepository : BaseRepository
{
public OracleRepository() : base(ConnectionString)
{
}
}
public abstract class BaseRepository
{
private string _connectionString;
public BaseRepository(string connectionString)
{
ConnectionString = ConfigurationManager.AppSettings[connectionString];
}
}
You can certainly keep the repository layer in the .net framework instead of using Core.
Instead of using the ConfigurationManager.AppSettings, I would suggest to inject the required settings in form of either KeyValuePair collection or Dictionary.
Then you can initialize this KeyValuePair collection or Dictionary in the startup method.

Logging using AOP in .NET Core 2.1

I want to implement AOP for the logging in my .NET Core 2.1 solution. I've never used it before and I've been looking online and cant seem to see any examples of people using it with Core 2. Does anyone know how i would go about this?
For example what packages to use for AOP and have any example code to get me started? Im using the built in DI with .net core so i dont need to worry about that part.
Microsoft DI does not offer advances scenarios such as interceptor or decorators(there is a workaround for decorators using Microsoft DI: https://medium.com/#willie.tetlow/net-core-dependency-injection-decorator-workaround-664cd3ec1246).
You can implement AOP by using Autofac (https://autofaccn.readthedocs.io/en/latest/advanced/interceptors.html) or Simple injector with dynamic proxy. Both have a really good documentation. Simple injector doesn't have an out of the box solution for interception because of their design rules but you can add an extension for it (http://simpleinjector.readthedocs.io/en/latest/aop.html).
Here is a basic AOP scenario from the official SI documentation:(http://simpleinjector.readthedocs.io/en/latest/InterceptionExtensions.html) :
//Add registration to the composition root
container.InterceptWith<MonitoringInterceptor>(serviceType => serviceType.Name.EndsWith("Repository"));`
// Here is an example of an interceptor implementation.
// NOTE: Interceptors must implement the IInterceptor interface:
private class MonitoringInterceptor : IInterceptor {
private readonly ILogger logger;
public MonitoringInterceptor(ILogger logger) {
this.logger = logger;
}
public void Intercept(IInvocation invocation) {
var watch = Stopwatch.StartNew();
// Calls the decorated instance.
invocation.Proceed();
var decoratedType = invocation.InvocationTarget.GetType();
this.logger.Log(string.Format("{0} executed in {1} ms.",
decoratedType.Name, watch.ElapsedMilliseconds));
}
}
Disclaimer: I am the producer of this solution
Microsoft does not provide an AOP solution out the box for Net Core. However, I have produced a 3rd party project which may help. It works directly with Net Core and plugs in via the ServiceCollection registration in your application.
What Microsoft does provide is a library called System.Runtime.DispatchProxy which can be used to create proxy objects for your classes. However, this proxy isnt particularly useful or feature rich on its own and would require a lot of extra code to get something that is on a level with Castle Proxy (the well known Dynamic Proxy library)
With that in mind, I have created a library which wraps the DispatchProxy into code that can be easily injected during the ServiceCollection configuration in the application startup. The trick is to have a way to create attributes AND a paired interceptor that can be applied to your methods. The attribute is then read during the Proxy wrapping and the relevant Interceptor is called.
This is an example Interceptor Attribute
public class ConsoleLogAttribute : MethodInterceptorAttribute
{
}
This is an example Interceptor class
public class ConsoleLogInterceptor : MethodInterceptor
{
public override void BeforeInvoke(IInterceptionContext interceptionContext)
{
Console.WriteLine($"Method executing: {interceptionContext.CurrentMethod.Name}");
}
public override void AfterInvoke(IInterceptionContext interceptionContext, object methodResult)
{
Console.WriteLine($"Method executed: {interceptionContext.CurrentMethod.Name}");
}
}
This is how it would be applied to your method
[ConsoleLog]
public void TestMethod()
{
}
And then finally, this is how it would be added to your ServiceCollection configuration (assuming that the class you wanted to Proxy was called [TestClass]:
public void ConfigureServices(IServiceCollection services)
{
// Configure Simple Proxy
services.EnableSimpleProxy(p => p.AddInterceptor<ConsoleLogAttribute, ConsoleLogInterceptor>());
// Configure your services using the Extension Methods
services.AddTransientWithProxy<ITestClass, TestClass>();
}
Take a look at this GitHub project: https://github.com/f135ta/SimpleProxy

Categories