Ensure that your project is referencing 'Microsoft.NET.Sdk.Web' and the 'PreserveCompilationContext' property is not set to false - asp.net-core

I have 2 projects ones call Api which is a library for my DbContext and other call AdminPanel which is an Asp.NetCore project for my website.
in The Api Project my Dbcontext inherit IdentityDbContext<AppUser> and the
Appuser class is in the same project in model folder which inherited from IdentityUser class.
Now in my AdminPanel in Startup.cs i use
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.User.RequireUniqueEmail = true;
config.Password.RequiredLength = 8;
})
.AddEntityFrameworkStores<MyDbContext>()
.AddDefaultTokenProviders();
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, AppClaimsPrincipalFactory>();
services.AddScoped<SignInManager<ApplicationUser>, AuditableSignInManager<ApplicationUser>>();
which ApplicationUser is a class in AdminPanel now when i run AdminPanel project i'll get
An error occurred during the compilation of a resource required to
process this request. Please review the following specific error
details and modify your source code appropriately.
Generated Code
One or more compilation references are missing. Ensure that your project is referencing 'Microsoft.NET.Sdk.Web' and the
'PreserveCompilationContext' property is not set to false.
The type or namespace name 'ApplicationUser' could not be found (are you missing a using directive or an assembly reference?)
I don't know what should i do.
beforehand Sorry about my English. Thanks for your help.

Related

Design Time DbContext Factory - Class Library how to get connection string from UserSecrets in a class library project?

I have separated my Database project as a class library. And I am defining a IDesignTimeDbContextFactory implementation. I want to use user-secrets to keep the config settings. I get an error as follows. How can i make this setup work?
Note: I have already setup the user-secrets for the class library project. And my user secrets has the necessary values:
{
"ConnectionStrings:CatalogDbContext": "Server=(localdb)\\\\mssqllocaldb;Database=Catalog;Trusted_Connection=True;MultipleActiveResultSets=true"
}
Project Structure:
Catalog
|---API(Web API)
|---Data(Class Lib)
|- appsettings.json
|- IDesignTimeDbContextFactory<CatalogDbContext>
Appsettings.json
{
"ConnectionStrings": {
"CatalogDbContext": ""
}
}
public class CatalogDbContextFactory : IDesignTimeDbContextFactory<CatalogDbContext>
{
public CatalogDbContext CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var dbContextOptionsBuilder = new DbContextOptionsBuilder<CatalogDbContext>();
var connectionString = configuration.GetConnectionString(nameof(CatalogDbContext));
dbContextOptionsBuilder
.UseSqlServer(connectionString);
return new CatalogDbContext(dbContextOptionsBuilder.Options);
}
}
This command fails with an error:
Catalog.Api> dotnet ef migrations add Catalog.Initial --project ..\Catalog.Data\Catalog.Data.csproj --verbose
Finding DbContext classes in the project...
Found DbContext 'CatalogDbContext'.
Using DbContext factory 'CatalogDbContextFactory'.
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.ArgumentNullException: Value cannot be null. (Parameter 'connectionString')
at Microsoft.EntityFrameworkCore.Utilities.Check.NotEmpty(String value, String parameterName)
at Microsoft.EntityFrameworkCore.SqlServerDbContextOptionsExtensions.UseSqlServer(DbContextOptionsBuilder optionsBuilder, String connectionString, Action`1 sqlServerOptionsAction)
I can clearly say this is because the connectionstring is empty. The user secrets configuration provided is not added to the list of providers. I don't know what the setup will look like to add user secrets to a class library project. Please help!
I tried as you mentioned and repeated your error in my case
then I modified the appsettings.json in webapi project and added the migration successfully this time,it still read the jsonfile in your webapi project

.Net Core : Class Library to connect to DB, DAL, User Secret and Asp.Net Core's Configuration

I have the following :
a class library with connection classes such as connection, command, parameter
a DAL with entities, mapper, interface, services as well as a static class that holds hard coded connectionString and InvariantName.
an Asp.Net Core project
References :
DAL has a reference to the class library to make use of its connection class to which it provides connectionString and InvariantName thanks to its static class etc..
Asp.Net has a reference to the DAL.
What I want :
I now want to use the User Secrets to store hard coded sensitive data connections and get rid off the static class.
I know I can use the the Asp.Net Core startup.cs to read the settings from Configuration and make use of binding to store them into a class and use DI.
My guess :
DI seems "easy" when used inside an Asp controller. But I need the settings values (connectionString and InvariantName) outside the Asp.Net Core to be injected into a constructor of a class somewhere in my DAL.
I guess I would then need to have to reference the Asp.Net Core project to my DAL. But then I would end up with a circular reference (DAL to Asp.Net Core and the opposite).
So what's the solution?
Have an intermediate library class into which I would retreive the settings values from Asp.Net Core and then pass them to my DAL (to prevent circular reference)?
Manually recreate the "Configuration process" inside the DAL and get settings there directly
Or something else that I don't know?
Ps : I am new in development and only have a few projects'experience in Asp.Net Framework so far..and it's my first Asp.Net Core project
I know I can use the the Asp.Net Core startup.cs to read the settings from Configuration and make use of binding to store them into a class and use DI
You already answered your own question with this. This is the correct and recommended behavior to setup DI for 3rd party libs and configurations. If you want to avoid clutter in Startup class, create an extension method:
namespace Microsoft.Extensions.DependencyInjetion
{
public static MyLibraryCollectionExtensions
{
public static IServiceCollection AddMyLibrary(this IServiceCollection services)
{
services.AddDbContext<MyDbContext>(...);
}
}
}
to register your classes. Alternatively, extend the method to accept a parameter delegate to configure it
namespace Microsoft.Extensions.DependencyInjetion
{
public static MyLibraryCollectionExtensions
{
public static IServiceCollection AddMyLibrary(this IServiceCollection services, Action<MyOptions> setup)
{
var defaultOptions = ... // i.e. new MyOptions();
// pass default options to be modified by the delegate
setup?.Invoke(defaultOptions);
// your registrations
services.AddDbContext<MyDbContext>(...);
}
}
}
And all the user has to do in your library is add
services.AddMyLibrary();
// or with setup
services.AddMyLibrary(config =>
{
config.MyConnectionString = Configuration.GetConnectionString("MyContext");
});
and store the connection string in the appsettings.json.
{
"ConnectionStrings":
{
"MyContext" : "MyConnectionString here"
}
}
I finally used the ConfigurationBuilder to get values from the appsettings.json file.
It's probably not the right way to do it but it is working with my DAL and Connection dlls.
In case it helps anyone else :

Instantiate DBContext and get its metadata from a Type (another project)

I have Project 1 which is an ASP.NET Core application and Project 2 which is a .NET Standard library.
Is there a way to instantiate a DbContext found in Project 1 from my library using only the Type? I only want to get the metadata about it.
How does Scaffolding do it?
Example
var context = InstatiateFromType(typeof(MyContext));
// So that I get access to the metadata
var x = context.Model.FindEntityType(...);
I'm not sure I understood correctly.
But instead of instantiating it yourself, you could use get an instance via DI in your constructor.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<MyContext>(options => options.UseSqlServer("connectionString"));
}
And then in your Class you just get it via the constructor.

What is causing the error that swagger is already in the route collection for Web API 2?

I installed Swagger in my ASP.Net MVC Core project and it is documenting my API beautifully.
My co-worker asked me to install it in a full framework 4.6.1 project so I've done the following.
In Package Console Manager run:
Install-Package Swashbuckle
To get your Test Web API controller working:
1) Comment this out in the WebApi.config:
// config.SuppressDefaultHostAuthentication();
// config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
Now this URL:
http://localhost:33515/api/Test
brings back XML:
<ArrayOfstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<string>value1</string>
<string>value2</string>
</ArrayOfstring>
In Global.asax Register() I call:
SwaggerConfig.Register();
In AppStart.Swagger.Config Register() I put:
public class SwaggerConfig
{
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1.0", "HRSA CHAFS");
c.IncludeXmlComments(GetXmlCommentsPath());
})
.EnableSwaggerUi(c =>
{});
}
private static string GetXmlCommentsPath()
{
var path = String.Format(#"{0}bin\Services.XML", AppDomain.CurrentDomain.BaseDirectory);
return path;
}
}
Now I get this error:
"A route named 'swagger_docsswagger/docs/{apiVersion}' is already in the route collection. Route names must be unique."
I've been stuck on this for hours.
How do you get rid of this?
This can happen when you re-name your .NET assembly. A DLL with the previous assembly name will be present in your bin folder. This causes the swagger error.
Delete your bin folder and re-build your solution.
This resolves the swagger error.
Swagger config uses pre-application start hook, so you don't need to call SwaggerConfig.Register() explicitly. Otherwise Register method is called twice.
[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]
in my case i added another project as refrence and that other project has swagger too.
i remove that refrence and move needed code to new project.
I solved the problem by deleting the SwaggerConfig.cs file from the App_Start folder as I had already created it manually.
Take a look at this link, here also has more useful information:
A route named 'DefaultApi' is already in the route collection error
In my experience the error occurs when you add reference to another project and that project is a service and it occurs on the SwaggerConfig of the referenced project. Removing project reference usually solve the problem, if you need to share classes I suggest you to create a specific project as Class Library and add its reference to both your services

Migration from WCF WebApi to MVC4 Api - Registering global error handler

I am migrating a project that was developed using WebApi Preview 5 (when it was part of WCF) to the final release of WebApi (part of MVC4). There is a document describing the process but it is extremely simplistic and doesn't cover most of the issues.
Now one of the issues I am facing is that a GlobalErrorHandler was created by inheriting from HttpErrorHandler and then overriding OnTryProvideResponse and that was used to hook error handling with Elmah. Now that was registered on AppStart with a line like this:
var configuration = new WebApiConfiguration();
//some other configuration for security and CreateInstance
configuration.ErrorHandlers =
(handlers, endpoint, description) => handlers.Add(new GlobalErrorHandler())
};
//then some registration
RouteTable.Routes.MapServiceRoute<SomeObject>("routeName", configuration);
and then mapping different route to this configuration. All this code doesn't work in the new world of MVC4 WebApi, it seems like there is a conflict between HttpErrorHandler and it can't even implement its members properly.
Now I've seen general posts about how to register Elmah with WebApi but I am trying to stick to the original code as much as possible and I am assuming - may be I am wrong - that there is a direct equivalent to what Microsoft had in the Preview version and what they released in the final one. So my questions:
What is the equivalent of this Global Error handling registation in ASP.NET MVC4 WebApi?
Do I need to do the configuration the same way it is done here (default webapi samples project doesn't seem to have similar code)
What is the equivalent of that route registration line of code: RouteTable.Routes.MapServiceRoute("routeName", configuration);
If you create a quick one-off WebApi MVC project in Visual Studio you will see an App_Start folder which contains some classes which have static methods for handling the registration, specifically:
FilterConfig.cs
WebApiConfig.cs
WebApi Config is where you need to register routes etc...
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Filter config is what you need to handle your global errors... Filter config has a default error handler attribute added which you can swap out or out
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
Global.asax calls these static registration scripts like so:
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
In regard to Elmah it appears simplying including the Nuget package will register it...
Look for the package Elmah.Mvc
PM> Install-Package Elmah.MVC
it used to be like this How to get ELMAH to work with ASP.NET MVC [HandleError] attribute? but now according to this blog it has changed:
HandleErrorAttribute inside If you tried to use ELMAH in ASP.NET MVC,
you are probably implemented your own HandleErrorAttribute, as it's
shown in this example. You no longer need to apply this custom code
with Elmah.MVC. As soon you installed package, so can safely remove
your HandleError attribute, since it's already included into package.
This now appears to register itself in the Web.Config as a managedHandler so your code does not need to reference Elmah directly.