PostgreSQL and Blazor .Net Core 3.1 - npgsql

Are there any resources on how to use the current version of Blazor (3.1) and PostgreSQL?
I've tried writing the simplest code, just to see whether it connects to the database but I get this error message: System.Net.Dns:GetHostByName is not supported on this platform
a button click would activate this code:
async void connection()
{
var connString = "Host=Server1;Username=postgres;Password=pass;Database=BlazorData";
try
{
await using var conn = new NpgsqlConnection(connString);
await conn.OpenAsync();
errcheck = "success";
}
catch (Exception ex)
{
errcheck = ex.Message;
}
}

I explain how I use it with entity framework. It might help you.
in startup.cs, ConfigureServices method have this
services.AddEntityFrameworkNpgsql().AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));
You need two packages to be installed through nuget
Npgsql.EntityFrameworkCore.PostgreSQL
Npgsql.EntityFrameworkCore.PostgreSQL.Design
in appsetting.json make sure you have setup connection string correctly, below one is mine. Host can be localhost if database is in the same machine as the database
"DefaultConnection": "Host=192.168.16.240;Port=5432;Username=postgres;Password=mypassword;Database=mydatabase;"
That's basically it.
then define a application db context with your tables
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<Room> Rooms { get; set; }
public DbSet<Meal> Meals { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
in package mangaer console
add-migration initial
update-database
you should see the tables created in PgAdmin.
and use your dbsets like usual c# lists. and remember to inject applicationdbcontext in the controllers you need it.

The error says you need to resolve the hostname by yourself. Either pass an IP address or use Dns.GetHostEntry
using System.Linq;
using System.Net;
using System.Net.Sockets;
...
async void connection()
{
var host = Dns.GetHostEntry("Server1");
var firstIpV4Address = host.AddressList.First(a => a.AddressFamily == AddressFamily.InterNetwork);
var connString = $"Host={firstIpV4Address};Username=postgres;Password=pass;Database=BlazorData";
try
{
await using var conn = new NpgsqlConnection(connString);
await conn.OpenAsync();
errcheck = "success";
}
catch (Exception ex)
{
errcheck = ex.Message;
}
}

Related

How connect to an existing Azure SQL database with ASP.NET CORE MVC using Entity Framework Core with migrations?

I have an app using Azure App Services with SQL server and SQL database that are connect to my web app on asp MVC. I've used Distributed Sql Server Cache as a table on my database and so far everything is working well and connected to each other.
Now I want to do two things:
Add entity framework to my app (I already have the database and
connection string)
Run migration – after I've published my app (If I've added for a
example new line or new
table, now I have new version)
I'm not sure how to do those things , I've looked up on many guides and couldn't find an answer. I found a post similar to mine – but using azure functions - here
. I would appreciate it if someone can help me with the steps that I need to follow (like they did in that post) to get entity framework and the migration.
Here is my code:
Program.cs-
using Microsoft.Extensions.Azure;
using Azure.Identity;
var builder = WebApplication.CreateBuilder(args);
if(!builder.Environment.IsDevelopment())
builder.Configuration.AddAzureKeyVault(new Uri(Environment.GetEnvironmentVariable("VaultUri")), new DefaultAzureCredential());
builder.Services.AddControllersWithViews();
builder.Services.AddAzureClients(clientBuilder =>
{
clientBuilder.AddBlobServiceClient(builder.Configuration["storage:blob"], preferMsi: true);
clientBuilder.AddQueueServiceClient(builder.Configuration["storage:queue"], preferMsi: true);
});
builder.Services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = builder.Configuration.GetConnectionString("db");
options.SchemaName = "dbo";
options.TableName = "_Cache";
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
Home Controller:
namespace WebAppAzure.Controllers
{
public class HomeController : Controller
{
private readonly BlobServiceClient storage;
private readonly ILogger<HomeController> logger;
private readonly IDistributedCache cache;
public HomeController(BlobServiceClient storage, ILogger<HomeController> logger,
IDistributedCache cache)
{
this.storage = storage;
this.logger = logger;
this.cache = cache;
}
public IActionResult Index()
{
var containerClient = storage.GetBlobContainerClient("public");
var blob = containerClient.GetBlobClient("image.jpeg");
var model = blob.Uri.ToString();
return View(model: model);
}
public IActionResult Privacy()
{
var stringModel = DateTime.Now.ToString();
cache.SetString("name", stringModel);
return View(model: $"SET: {stringModel}");
}
public IActionResult About()
{
var stringModel = cache.GetString("name");
return View(model: $"GET: {stringModel}");
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
Add entity framework to my app (I already have the database and connection string)
Use below code for add Entity framework and upload to azure app service and run migration command to migrate database.
DBcontext file in project.
using Microsoft.EntityFrameworkCore;
using WebApplication_72783922.Entity;
namespace WebApplication_72783922
{
public class DbConnectionEntity : DbContext
{
public DbConnectionEntity()
{
}
//string connectionString = Environment.GetEnvironmentVariable("ConnectionStrings:dbcon").ToString();
public DbConnectionEntity(DbContextOptions<DbConnectionEntity> options)
: base(options)
{
}
public virtual DbSet<Users> users { get; set; }
public virtual DbSet<department> Departments { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=xxxx;Initial Catalog=database;Persist Security Info=False;User ID=adminserver72783922;Password=xxxx;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
}
Program.cs File code.
using Microsoft.Extensions.Azure;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
var builder = WebApplication.CreateBuilder(args);
if (!builder.Environment.IsDevelopment())
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = "Server=xxxx;Initial Catalog=database;Persist Security Info=False;User ID=adminserver72783922;Password=xxxx;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";
options.SchemaName = "dbo";
options.TableName = "_Cache";
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Run migration – after I’ve published my app
Enable Migration using this command on Package Manager Console enable-migrations
Then add-migration InitialCreate
Then create migrationadd-migration test-v1
update database update-database -verbose

Topshelf: Issues using NancyFX with Topshelf 4.2.1

I am trying to develop a data access service using Visual Studio 2019, .Net Core 3.0. I am using NancyFX to handle http requests. this is working just fine as a console application. When I build and run, then in browser go to HTTP://localhost/, it returns the proper data. I have a working Nancy module to handle requests. Here is original Main code:
static void Main(string[] args)
{
Logger.LogInfo("NancyDataService starting...");
var uri = new Uri(ConfigurationManager.AppSettings["uri"]);
var hostConfig = new HostConfiguration();
hostConfig.UrlReservations.CreateAutomatically = true;
hostConfig.RewriteLocalhost = false;
using (var nancyHost = new NancyHost(uri, new AppBootstrapper(), hostConfig))
{
try
{
nancyHost.Start();
Console.WriteLine($"Nancy now listening on {uri}.\n\nPress any key to exit");
Logger.LogInfo($"Nancy now listening on {uri}...");
}
catch (Exception ex)
{
Logger.LogError(ex.Message);
Console.WriteLine("Error " + ex.Message + "\n\nPress any key to exit");
}
Console.ReadKey();
Logger.LogInfo("NancyDataService stopped...");
}
}
Now I want to make it a Windows Service. First try is with Topshelf. The following Main code is basically taken from Topshelf documentation and other articles about Topshelf.
static void Main(string[] args)
{
Logger.LogInfo("NancyDataService starting...");
var rc = HostFactory.Run(x =>
{
x.Service<DataService>(s =>
{
s.ConstructUsing(name => new DataService());
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
x.RunAsLocalSystem();
x.StartAutomatically();
x.EnableServiceRecovery(r => r.RestartService(TimeSpan.FromSeconds(10)));
x.SetServiceName("NancyDataService");
});
var exitCode = (int)Convert.ChangeType(rc, rc.GetTypeCode()); //11
Environment.ExitCode = exitCode;
}
Here is my DataService class, basically built from the Topshelf docs and a couple of articles I found:
class DataService
{
public DataService()
{
}
private SemaphoreSlim _semaphoreToRequestStop;
private Thread _thread;
public void Start()
{
// start Nancy here
var uri = new Uri(ConfigurationManager.AppSettings["uri"]);
var hostConfig = new HostConfiguration();
hostConfig.UrlReservations.CreateAutomatically = true;
hostConfig.RewriteLocalhost = false;
using var nancyHost = new NancyHost(uri, new AppBootstrapper(), hostConfig);
try
{
nancyHost.Start();
Console.WriteLine($"Nancy now listening on {uri}...");
Logger.LogInfo($"Nancy now listening on {uri}...");
// spin thread here
_semaphoreToRequestStop = new SemaphoreSlim(0);
_thread = new Thread(DoWork);
_thread.Start();
}
catch (Exception ex)
{
Logger.LogError(ex.Message);
Console.WriteLine($"Error: {ex.Message}");
}
}
private void DoWork(object obj)
{
while (true)
{
Console.WriteLine("doing work..");
if (_semaphoreToRequestStop.Wait(500))
{
Console.WriteLine("Stopped");
break;
}
}
}
public void Stop()
{
Logger.LogInfo("NancyDataService stopping...");
_semaphoreToRequestStop.Release();
_thread.Join();
//return true;
}
}
So now when I run the project in design mode (which Topshelf says you should be able to do), it seems to start fine and Nancy seems to be listening on the right port. However, when I go to the browser and type in HTTP//localhost:8080/, I get "This site can't be reached. localhost refused to connect"
I have the latest version of Topshelf (4.2.1) and Topshelf.Log4Net packages.
Can anyone shed any light on this? Thanks...
Solved this issue. Turned out to be incorrect scoping of my NancyHost object. Works fine now.

Callback method on the SignalR Wpf client side

I have 2 .NET solutions. One is asp.net mvc web application which is signalr server. The other is SignalR WPF client that consumes the collection of custom class objects from the web signalr server. I run the signalr MVC web server with IIS. The signalr WPF client application is run in another VS instance.
The SignalR web server has a Hub method (named "MessageLogHub", please see the below codes) that uses SqlDependency to broadcast collection of custom class objects to all signalr clients if there is a change (e.g. manually inserting data into the SQL Server database table) in a target database table. The collection of custom class objects are all of the records of a SQL Server database server.
From the signalr WPF client application side, I let the client register the SignalR server method as follows:
Proxy.On<List<MessageLog>>("BroadcastMessage", OnBroadcastMessage);
And the call back method named "OnBroadcastMessage" looks like:
private void OnBroadcastMessage(List<MessageLog> logs)
{
// problem: this callback method is hits once there is a put from signalr server. but the "logs" parameter's value is never changed !!!
Dispatcher.Invoke(() =>
{
textblockTime.Text = DateTime.Now.ToLongTimeString() + " - logs.Count=" + logs.Count();
datagridLogs.ItemsSource = null;
datagridLogs.ItemsSource = logs;
});
}
So when there is a change of database, the SignalR web server will calls the method "BroadcastMessage" on all connected clients (please see the below Signalr Hub server codes) and the callback method (on the SignalR WPF client codes) "OnBroadcastMessage" will be fired automatically on clients (WPF or web app clients). In VS, I debugs the call back method named "OnBroadcastMessage" and I see it is hit when there is a change in the database that triggers the SignalR server codes to broadcast to all connected clients.
The problem is in the signalr Wpf client callback method of "OnBroadcastMessage" (please see the above code of callback method of "OnBroadcastMessage"), the value of the "logs" parameter is not changed anytime the debug break-point is hit in that callback method. If a row is inserted in the database table, then the returned value of "logs" parameter is supposed to be changed and the new "logs" parameter is put to the signalr client side. Please help me.
I have another signalr asp.net MVC web project that is signalr client and it is embedded in the SignalR MVC web server solution. It works fine with the signalr server and I see the changes in real time way with that signalR web client. But the signalr WPF client application is not working as mentioned above.
Here are the codes (the xaml code behind file) for signalr WPF client application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using MessageWatchWpfClient.Models;
using Microsoft.AspNet.SignalR.Client;
namespace MessageWatchWpfClient
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string hostUrl = "http://localhost/MessageWatch/signalr";
public IHubProxy Proxy { get; set; }
public HubConnection Connection { get; set; }
public MainWindow()
{
InitializeComponent();
}
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
Connection = new HubConnection(hostUrl);
Proxy = Connection.CreateHubProxy("MessageLogHub");
// 1) Register so that Server automatically calls Client when database is changed
Proxy.On<List<MessageLog>>("BroadcastMessage", OnBroadcastMessage);
await Connection.Start();
// 2) Client calls Server on the Wpf application loading and the following is run one time only
await Proxy.Invoke<List<MessageLog>>("GetAllMessagesLog")
.ContinueWith((t) =>
{
Dispatcher.Invoke(() =>
{
textblockTime.Text = DateTime.Now.ToLongTimeString() + " - logs.Count=" + t.Result.Count();
datagridLogs.ItemsSource = t.Result;
});
}
);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void OnBroadcastMessage(List<MessageLog> logs)
{
// problem: this callback method is hits once there is a put from signalr server. but the "logs" parameter's value is never changed !!!
Dispatcher.Invoke(() =>
{
textblockTime.Text = DateTime.Now.ToLongTimeString() + " - logs.Count=" + logs.Count();
datagridLogs.ItemsSource = null;
datagridLogs.ItemsSource = logs;
});
}
}
}
The following codes are for SignalR Hub class on the server side application that is Asp.net MVC web and is hosted on IIS:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using MessageWatch.Models;
using Microsoft.AspNet.SignalR;
using SD = SignalR.Dal;
using MessageWatch.Utils;
namespace MessageWatch.Hubs
{
public class MessageLogHub : Hub
{
NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();
public IEnumerable<MessageLog> GetAllMessagesLog()
{
var messageList = new List<MessageLog>();
try
{
var conStr = ConfigurationManager.ConnectionStrings["SignalRDatabase"].ToString();
var connection = new SqlConnection(conStr);
const string query = "SELECT Message,EventID,LL.Name as LogLevelID,OC.Name as OperationCodeID,ML.ServerName,ML.ComponentName,ML.SubComponentName FROM [dbo].[MessageLog] ML inner join [dbo].[LogLevel] LL on ML.LogLevelID = LL.ID inner join [dbo].[OperationCode] OC on ML.OperationCodeID = OC.ID order by ML.ID desc";
SqlDependency.Start(conStr); // to avoid error "When using SqlDependency without providing an options value, SqlDependency.Start() must be called prior to execution of a command added to the SqlDependency instance."
var command = new SqlCommand(query, connection);
var dependency = new SqlDependency(command);
//If Something will change in database and it will call dependency_OnChange method.
dependency.OnChange += dependency_OnChange;
connection.Open();
var da = new SqlDataAdapter(command);
var dt = new DataTable();
da.Fill(dt);
for (var i = 0; i < dt.Rows.Count; i++)
{
var ml = new MessageLog
{
Name = dt.Rows[i]["Message"].ToString(),
EventID = Convert.ToInt32(dt.Rows[i]["EventID"].ToString()),
LogLevelName = dt.Rows[i]["LogLevelID"].ToString(),
OperationCodeName = dt.Rows[i]["OperationCodeID"].ToString(),
ServerName = dt.Rows[i]["ServerName"].ToString(),
ComponentName = dt.Rows[i]["ComponentName"].ToString(),
SubComponentName = dt.Rows[i]["SubComponentName"].ToString()
};
messageList.Add(ml);
}
}
catch (Exception ex)
{
_logger.Error(CultureInfo.CurrentCulture, "{0}", ex.Message);
}
return messageList;
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
SendNotifications();
}
}
private void SendNotifications()
{
var messageList = GetAllMessagesLog();
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MessageLogHub>();
context.Clients.All.broadcastMessage(messageList);//Will update all the clients with message log.
}
public void CreateData()
{
try
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MessageLogHub>();
var dbContext = new SD.SignalREntities();
var repository = new SD.GenericRepository(dbContext);
var ml = new DataRandomer().Create();
repository.Add(ml);
dbContext.SaveChanges();
context.Clients.All.createData();
}
catch (Exception ex)
{
_logger.Error(CultureInfo.CurrentCulture, "{0}", ex.Message);
}
}
}
}

Testing this command

I'm quite new to unit tests and I've got some troubles testing this command
internal async Task OnDeleteTreasurerCommandExecute(TesorieraItemResult tesoriera)
{
try
{
if (await MessageService.ShowAsync("Confermare l'operazione?", string.Empty, MessageButton.YesNo, MessageImage.Question) == MessageResult.Yes)
{
await repository.DeleteTesorieraItemAsync(tesoriera.ID_ISTITUTO,tesoriera.ID_DIVISA,tesoriera.PROGRESSIVO);
await MessageService.ShowInformationAsync("Operazione completata");
if (SelectedInstitute != null)
await OnLoadDataCommandExecute();
}
}
catch (Exception ex)
{
ErrorService.HandleError(GetType(), ex);
}
}
I'm using Catel as MVVM framework
how do I simulate the yes/no answers?
Thanks
You need to substitute the MessageService with a class that can return yes or no answer. Here's an example using NSubstitute.
Install-Package NSubstitute
Install-Package NUnit
Let us say you have a class that has a method that
needs Yes, then No:
public class AccountViewModel
{
readonly IMessageService _messageService;
readonly ICustomerRepository _customerRepository;
public AccountViewModel(IMessageService messageService, ICustomerRepository customerRepository)
{
_messageService = messageService;
_customerRepository = customerRepository;
}
public async Task OnDeleteCustomer(Customer customer)
{
if (await MessageService.ShowAsync(
"Confirm?",
string.Empty,
MessageButton.YesNo,
MessageImage.Question) == MessageResult.Yes)
{
_customerRepository.Delete(customer);
await MessageService.ShowInformationAsync("Completed");
}
}
}
Then your test case looks like this:
public class TestAccountViewModel
{
[TestCase]
public class TestDeleteCustomer()
{
// arrange
var messageService = Substitute.For<IMessageService>();
messageService
.ShowAsync(
Arg.Any<string>(),
Arg.Any<string>(),
Arg.Any<MessageButton>(),
Arg.Any<MessageImage>())
.Returns(Task.FromResult(MessageResult.Yes);
messageService
.ShowInformationAsync(Arg.Any<string>())
.Returns(Task.FromResult<object>(null));
var customerRepository = Substitute.For<ICustomerRepository>();
// act
var sut = new AccountViewModel(messageService, customerRepository);
var customer = new Customer();
sut.OnDeleteCustomer(customer);
// assert
Assert.IsTrue(customerRepository.Received().DeleteCustomer(customer));
}
}
In a past version, Catel provided a test implementation of the IMessageService that allowed you to queue expected results so you could test the different paths inside a command.
I just noticed this class is no longer available, but you can easily implement a test stub yourself (using mocking, etc). Or you could contribute to Catel and revive the test implementation.

It it possible to use existing SQLite database in windows phone?

I am newbie to windows phone development. I have a requirement to develop a app which was developed in Android and iOS. I need to use the same SQLite database which was used in Android and iOS. Is it possible to use existing SQLite database in windows phone? If it is yes how to do it ?
for basic setup of sqlite use this link
first add the database file to project and change its properties to COPYALWAYS and "CONTENT" and now copy it to you local folder and make connection to the database using sqlite like this.
public static SQLiteAsyncConnection connection;
public static bool isDatabaseExisting;
public static async void ConnectToDB()
{
try
{
StorageFile storageFile = await ApplicationData.Current.LocalFolder.GetFileAsync("DatabaseFinal.db");
isDatabaseExisting = true;
}
catch
{
isDatabaseExisting = false;
}
if (!isDatabaseExisting)
{
try
{
StorageFile databaseFile = await Package.Current.InstalledLocation.GetFileAsync("DatabaseFinal.db");
await databaseFile.CopyAsync(ApplicationData.Current.LocalFolder);
isDatabaseExisting = true;
}
catch
{
isDatabaseExisting = false;
}
}
if(isDatabaseExisting)
connection = new SQLiteAsyncConnection(Path.Combine(ApplicationData.Current.LocalFolder.Path, "DelhiMetroDatabaseFinal.db"), true);
}
}
}
this will create your connection too and for using databse for getting data from your db file use can use query like this
public List<dataclass> getdata(string line_id, ref Boolean isdata)
{
List<datadataclass> query = new List<datadataclass>();
try
{
query = dal.connection.Table<dataclass>().Where(i => i._id == line_id).ToListAsync().Result;
isdataclass = true;
return query;
}
catch (NullReferenceException e)
{
isdataclass = false;
}
return query;
}
data class will have properties as your column defined in you database.
class dataclass
{
public string _id { get; set; }
public string name { get; set; }
public int location { get; set; }
}

Resources