SQLite data context in AspNetCore app not working - sqlite

I have been trying to implement data access in my single page web app using the most recent scaffolding in Visual Studio 2019 and Entity Framework Core . I am using SDK version 3.1.100. Everything builds and runs but I am getting a runtime exception claiming "no such table: User". This makes me think that the connection between EF core and the database is good. Could be anything else as I am not having much luck with debugging. My SQLite database file and sqlite3.dll are contained in the project and have properties set to copy to output. The relevant code portions follow:
appsettings.json:
{
"ConnectionStrings": {
"Sqlite": "Data Source=HopeApp.db"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
The following added to ConfigureServices in Startup.cs:
services.AddEntityFrameworkSqlite()
.AddDbContext<DatabaseContext>(options =>
options.UseSqlite(Configuration.GetConnectionString("Sqlite")));
The database context:
public class DatabaseContext: DbContext
{
public DbSet<datUser> User { get; set; }
public DbSet<datIESum> IESum { get; set; }
//
// https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext
//
public DatabaseContext(DbContextOptions<DatabaseContext> options)
: base(options) { }
}
And finally, the controller that attempts to retrieve the data:
[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
private readonly DatabaseContext db;
public UserController(DatabaseContext db)
{
this.db = db;
}
[HttpGet]
public IEnumerable<datUser> Get()
{
List<datUser> users = new List<datUser>();
using (this.db)
{
foreach (var user in this.db.User)
{
users.Append(user);
}
}
return users;
}
}
I examine the SQLite .db file in DB Brower and see the tables are present and verify that data is present. I have checked file permissions so everyone has full control. I don't know what else to check to track this down. Note that most of the examples these days are provided as "code first" instead of "database first" which works better for my application.
Here is a screen shot of HopeApp.db:
The error:
An exception of type 'Microsoft.Data.Sqlite.SqliteException' occurred in
Microsoft.EntityFrameworkCore.Relational.dll but was not handled in user code
SQLite Error 1: 'no such table: User'.
Any ideas or debugging suggestions? Any more information I can provide?

The error mentions that table User can not be found but the database file has table datUser.
The name of the property in the database context determines the expected table name. Either rename it to match, change the database file to match or use the fluent API to map between the two.
More information can be found here: https://learn.microsoft.com/en-us/ef/core/modeling/relational/tables

Related

Azure Application Insights not showing data

I have an ASP.NET Core application running as Azure App Service. Azure Application Insights is enabled (I followed these instructions). The problem is my instance of Azure Insights on Azure Portal isn't showing any useful data except for Live Metrics (see the screenshot). As you can see there are multiple requests and custom events on the screenshot.
However, when I open Transaction search it shows nothing (see the screenshot).
Events page is empty as well (see the screenshot).
So far I double-checked an InstrumentKey. Also I tried to use ConnectionString instead of InstrumentKey, but it didn't help.
My app is running on .NET Core 3.1. I installed the latest version of Microsoft.ApplicationInsights.AspNetCore package which is 2.19.0.
Here is how logging is configured in Program.cs:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureLogging(builder =>
{
builder.AddFilter<ApplicationInsightsLoggerProvider>("", LogLevel.Information);
});
And below is code from Startup.cs:
services.AddApplicationInsightsTelemetry(new ApplicationInsightsServiceOptions
{
ConnectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING")
});
LogLevel is also configured in appsettings.json:
"Logging": {
"LogLevel": {
"Default": "Warning"
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
}
}
Update:
My Admin who has more permissions can see all data, including events, performance operations etc. So I suppose there's something to do with permissions. Though it's strange that I'm not seeing any warning messages. The Admin assigned me more roles (see the screenshot), but it didn't make any difference.
I would appreciate any help on this issue!
After tearing almost all hair off my head I finally solved the issue!
Turned out the instance of Azure Application Insights was linked to a Log Analytic Workspace that belonged to a Resource Group to which I didn't have access. So logs were stored properly, but I didn't have permission to read them.
My admin solved the issue by creating a new instance of Azure Application Insights which was linked to a Log Analytic Workspace within my Resource Group.
To anyone who isn't familiar with Log Analytic Workspace - it can be specified when you create a new instance of Azure Application Insights (see the screen).
Thanks everyone for trying to help me!
UPDATE: As Jonathan L. mentioned in the comments, instead of creating a new Application Insights instance, one can just change Workspace in Properties.
I have tried the same and can able to see the logs inside portal .
As Peter Bons suggested make sure that you are using ILogger in your controller .
Here are the steps i have followed .
I have download an sample project from GitHub and after extract open project in Visual studio and configure with Application insight telemetry . Updated latest Microsoft.ApplicationInsights.AspNetCore to 2.19.0
And added instrumentation key in my appsettings.json which copied from Azure portal>Application insight(my applnsight)>overview.
{
"Logging": {
"ApplicationInsights": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Error"
}
},
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ApplicationInsights": {
"InstrumentationKey": "mykey",
"ConnectionString": "InstrumentationKey=6xxxxxx-xxxxx-xxxx-xxxx-0000000xxxxxxxx.in.applicationinsights.azure.com/"
}
}
Ilogger configuration in my controller.cs
namespace ApplicationInsightsTutorial.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var iteracion = 4;
_logger.LogDebug($"Debug {iteracion}");
_logger.LogInformation($"Information {iteracion}");
_logger.LogWarning($"Warning {iteracion}");
_logger.LogError($"Error {iteracion}");
_logger.LogCritical($"Critical {iteracion}");
try
{
throw new NotImplementedException();
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message);
}
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
In startup.cs added
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddApplicationInsightsTelemetry();//telemetry added
}
After all that above configuration run the application and navigate to Azure portal to check the logs .
Make sure that you have provided the log information which you want to check as example in my controller.cs .
from the logs we can see the exceptions/errors with line of code as well .
Here are some screenshot for reference:
For more information please refer this SO Thread .

Properties Added with Aspects Not in Generated JSON Schema

I'm trying to generate JSON Schemas using Newtonsoft JSON Schema. Regular properties added in my POCO class are added to the schema when it is generated. I'm also using PostSharp Aspects to add properties, but none of those are added to the schema.
This is a Console application targeting .NET 4.7.2.
Here is my Console application:
public class Program
{
private static void Main(string[] args)
{
JSchemaGenerator gen = new JSchemaGenerator();
JSchema schema = gen.Generate(typeof(MyClass));
File.WriteAllText("C:\\Temp\\TestSchema.json", schema.ToString());
}
}
Here is my aspect:
[PSerializable]
public class TestAspect : InstanceLevelAspect
{
[IntroduceMember]
[JsonProperty(Required = Required.Always)]
public string AspectProp { get; set; }
}
And here is my POCO:
[TestAspect]
public class MyClass
{
public int MyProperty { get; set; }
}
Finally, here is the generated schema:
{
"type": "object",
"properties": {
"MyProperty": {
"type": "integer"
}
},
"required": [
"MyProperty"
]
}
The MyProperty property is in the schema, but AspectProp - the property added by the aspect - is not.
When I open the exe in a decompiler, I can see that AspectProp is actually added to MyClass:
I'm not sure if this is a problem with PostSharp or Newtonsoft JSON Schema or if I'm doing something wrong. It seems like this should be possible.
Edit 1: 20 May
I split my solution out into separate projects - one for the Console app, one for the Aspect and one for MyClass. After making sure I was referencing the generated MyClass DLL directly (i.e. not a project reference, I actually removed the project once MyClass was built) it did not make a difference. AspectProp is still not in the schema. Based on this and the serialization suggested below by #dbc, this leads me to believe it is a problem with the Newtonsoft schema generator
Edit 2: 20 May
Per Antonin's Answer below, I created a new ContractResolver:
public class AspectPropertyResolver : DefaultContractResolver
{
public AspectPropertyResolver()
{
SerializeCompilerGeneratedMembers = true;
}
}
And then registered it in my app before calling Generate:
gen.ContractResolver = new AspectPropertyResolver();
Now my schema includes the aspect-generated property.
Newtonsoft.Json has an opt-in feature to serialize compiler-generated properties. See Newtonsoft.Json.Serialization.DefaultContractResolver.SerializeCompilerGeneratedMembers property.

Xamarin.Forms and EntityFrameworkCore 3.x how to properly create a database and apply migrations?

what is the proper way to create an EF Core database on an Android/iOS device with Xamarin.Forms and EntityFrameworkCore?
I've come across the EnsureCreated vs Migrate thing and since I'm planning on changing the database structure in the future, I'd like to be able to apply those migrations to an existing database, thus I've chosen the Migrate approach.
However, when I call the Migrate method, it doesn't seem to create a database. I've managed to make it work in case I copy the pre-generated database file on the devices beforehand, but that's not what I want. Is there a way to tell EF Core to check if there's an existing database, create a new database if not, and then apply pending migrations to it?
Here's what I've done so far:
I've created a .net standard class library "Data" that will hold all my database classes (context, models, and migrations).
I've changed the TargetFramework of the "Data" project from <TargetFramework>netstandard2.0</TargetFramework> to <TargetFrameworks>netcoreapp2.0;netstandard2.0</TargetFrameworks> so I could run PMC commands on it.
I've installed these nuget packages to the "Data" project:
EntityFrameworkCore
EntityFrameworkCore.Sqlite
EntityFrameworkCore.Tools
EntityFrameworkCore.Design
I've created a database context class. I've made two constructors for it. The default one will only be used by the PMC commands for generating migrations. The other one will be used in production.
public class MyTestContext : DbContext
{
private string _databasePath;
public DbSet<Issue> Issues { get; set; }
[Obsolete("Don't use this for production. This is only for creating migrations.")]
public MyTestContext() : this("nothing.db")
{
}
public MyTestContext(string databasePath)
{
_databasePath = databasePath;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//I've also tried Filename={_databasePath} here, didn't work either
optionsBuilder.UseSqlite($"Data Source={_databasePath}");
}
}
I've created a test model class, just to have something to play with
public class Issue
{
public string Id { get; set; }
}
I created an inital migration using this command, which completed successfully:
Add-Migration Migration001 -Context MyTestContext -Output Migrations
I added a call to the Migrate method in the App.xaml.cs of my Xamarin.Forms project to test if it works.
public partial class App : Application{
//... other code
protected override async void OnStart()
{
base.OnStart();
using (var db = new MyTestContext(_dbPath))
{
try
{
db.Database.Migrate();
db.Issues.Add(new Issue
{
Id = "TestIssueId"
});
db.SaveChanges();
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
//... other code
}
The _dbPath variable contains this (on Android where I'm testing it):
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "test.db");
After all this, I'm getting this exception:
Microsoft.Data.Sqlite.SqliteException: SQLite Error 1: 'no such table: Issues'.

Deployed SQLite database is empty after deployment of Universal App

I use in SQLite database in UWP. It has a few tables and is located in Assets folder and has build action marked as "Content".
Under development machine it works fine.
But after deployment to MS Windows 10 tablet it has the error
SQLite error 1 no such table Companies
It corresponds to the code
using (MobileContext db = new MobileContext())
{
companiesList.ItemsSource = db.Companies.ToList();
...
}
var createdResult = Database.EnsureCreated(); // It gives false so
I assume based on https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.infrastructure.databasefacade.ensurecreated?view=efcore-2.1 that database exists.
I have tried
optionsBuilder.UseSqlite("Data Source=" + ApplicationData.Current.LocalFolder.Path + #"\Mobile.db");
optionsBuilder.UseSqlite("Data Source=Mobile.db");
Any clue folk? Thanks!
P.S. I use Microsoft.EntityFrameworkCore to accees SQLite.
P.S. #2 I have tried this solution https://social.msdn.microsoft.com/Forums/en-US/1a933b13-09ee-46ec-9045-e2f567b6048c/uwp-sqlite-error-1-no-such-table-name-table?forum=wpdevelop but it does not work.
Derive from official document,
Connection strings in a UWP application are typically a SQLite connection that just specifies a local filename. They typically do not contain sensitive information, and do not need to be changed as an application is deployed. As such, these connection strings are usually fine to be left in code, as shown below. If you wish to move them out of code then UWP supports the concept of settings
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=blogging.db");
}
}
And the default path of db file is application LocalFolder. It looks like this C:\Users\vxx\AppData\Local\Packages\e045f456-27d9-4966-b639-01e2281b249f_7jxxxxxxxxxx\LocalState. If your configuration is same as above, when deploy in new machine, the content of db file is empty.
OP Update
I just commented some decorations of the class like [Table("Companies")] and [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] and it works now!

Accessing Configuration Settings in Javascript using ASP.NET Core 2 MVC

I'm currently building a simple website using ASP.NET Core 2 and bootstrap. The site will be deployed to a staging and production environment so I want to be able to configure some settings using Configuration Key/Value pairs I can set in Azure. I also want these values to be available to me in Javascript.
Thanks to this helpful blog post I have worked out how to create an AppSettings class and populate it. This post also covers using dependency injection to access AppSettings from a RazorPage model.
My appsettings.json file
{
"AppSettings": {
"TestProperty": "Test_Property"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
Automatically bind my AppSettings class in Startup.cs
services.Configure<AppSettings>(Configuration.GetSection(nameOf(AppSettings)));
Accessing the settings via dependency injection:
public class HomeModel : PageModel
{
private readonly AppSettings _appSettings;
public string TestProperty {get; set;}
public HomeModel(IOptions<AppSettings> appSettings)
{
_appSettings = appSettings.Value;
}
public IActionResult Index()
{
TestProperty = _appSettings.TestProperty;
return View();
}
}
Then on the page where I want to use this property in javascript I do the following to create a javascript property with the setting:
<script type="text/javascript">
var testProperty = '#Model.TestProperty';
</script>
This works but ideally I don't want to have to configure every page to use this dependency injection and expose my TestProperty on every page. I would like to be able to put the above code in my _Layout.cshtml in which every page's body is rendered (or somewhere else appropriate) so I can create a javascript variable for use on every page.
I have thought about using a BaseViewModel from which all my page's models are inherited but experimenting with this hasn't resulted in anything useful (just a exceptions).
How would you go about creating a javascript property from a configuration setting with the ability to configure only once?
I've come up with something that works the way I need but very interested to hear other suggestions, my way could well be far from the best..
I stumbled across this blog post which talks about the MVC6 keyword, #inject. Using this it is possible to inject dependencies into Razor views.
Using this I added the following to the top of my _Layout.cshtml file:
#inject IAppSettings AppSettings;
I could then reference properties of AppSettings in this view using:
<script type="text/javascript">
var testProperty = '#AppSettings.TestProperty';
</script>
I then edited my Startup.cs class to register IAppSettings and creates an AppSettings factory that reads the appsettings.json file and makes a new AppSettings class when required:
services.AddSingleton<IAppSettings, AppSettings>(e => Configuration.GetSection(nameof(AppSettings)).Get<AppSettings>());
This works a treat and I can access my javascript testProperty everywhere in my application but I'm curious if anyone has any other ideas as to how this could be done differently (perhaps using a BaseViewModel)?
Updated:
As requested, here is more information on my implementation:
My IAppSettingsService interface:
public interface IAppSettingsService
{
string AzureStorageAccountName { get; }
string AzureStorageAccountKey { get; }
}
My AppSettingsService implementation:
public class AppSettingsService : IAppSettingsService
{
public string AzureStorageAccountName { get; set; }
public string AzureStorageAccountKey { get; set; }
}
The AppSettings.json:
{
"AppSettings": {
"AzureStorageAccountName": "XXXXXXXXXX",
"AzureStorageAccountKey": "XXXXXXXXXX"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
Then in the Azure Portal I can change these values at any time using AppSettings:AzureStorageAccountName and setting the value to the required information in the App Settings section.
not sure what exactly you are trying to achieve. But pretty much what you have is the way you will access the appsettings in JavaScript. Injecting objects/services to view is a great thing in ASP.NET Core.
if you are just looking at URLs for different environments - you can achieve it in your release pipelines. In my day job - i work on a web app which is asp.net core as host + angular 2 as UI framework. We have 4 environments. angular code always makes call to our asp.net core host. we have a middleware written which looks for api calls and forwards them to our APIs hosted on azure in respective environments. The domain of the api environment is kept as an appsetting key. In our release pipeline - we override the property for each environment release.
Its best to centralize everything in your asp.net server side code. The UI i.e. JavaScript should just ping your server side MVC controller end point. That way you can parameterize the application settings during release.
hope this helps.

Resources