EF 4.1 Code First Initialization - Alternative - asp.net

I am building a web application using the entity framework and the code first approach and I really like it so far except one thing. The initialization process and seeding data is crap.
I have set it up as recommended with ASP.NET MVC with the setinitialiser being called in app start and a custom initialization class to add data but it always seems to fail silently and never work. (The database creation works just the data init fails)
Can anyone provide recommended paractice for this or a way to run an sql script from a file.
The given method for adding data, especially for a demo site seems cumbersome and I would prefer the ability to just run a database script directly from a file that is run once as part of an install process rather than depending on a process that fails without any indication that something has gone wrong.
EDIT
I have noticed it throwing exceptions ( idiotic datetime -> datetime2 conversion errors that should be handled by the entity framework.)
But part of the problem may be that my version of express 2010 is not breaking on errors it seems to be very buggy when debugging.
But the issue still stands. I find it a cumbersome and buggy way of essentially running sql scripts on the database. And don't want to end up with a huge set of methods and classes just to setup a demo site when someone installs my web application in IIS.

If you want to run SQL scripts from your initializer I would recommend adding
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
string scriptDirectory = HttpContext.Current.Server.MapPath("~/SqlScripts");
string sqlConnectionString = context.Database.Connection.ConnectionString;
DirectoryInfo di = new DirectoryInfo(scriptDirectory);
FileInfo[] rgFiles = di.GetFiles("*.sql");
foreach (FileInfo fi in rgFiles)
{
FileInfo fileInfo = new FileInfo(fi.FullName);
using (TextReader reader = new StreamReader(fi.FullName))
{
using (SqlConnection connection = new SqlConnection(context.Database.Connection.ConnectionString))
{
Server server = new Server(new ServerConnection(connection));
server.ConnectionContext.ExecuteNonQuery(reader.ReadToEnd());
}
reader.Close();
reader.Dispose();
}
}
The reason for using the SqlServer Management Objects is that you can use "GO" in your scripts. it then becomes incredibly easy to script from SSMS and paste the scripts into your SqlScripts directory.
You can find the SMO Libraries at:
C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll
C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.Management.Sdk.Sfc.dll
C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.Smo.dll
and if you need help scripting your data
SP_Generate_Inserts

Until you will show reproducible code snippet where initialization fails without throwing an exception I hardly believe that this happens.
You can always execute any SQL script by falling back to classic ADO.NET with SqlConnection and SqlCommand. Just open the file, load commands into string and execute them with SqlCommand or Database.ExecuteSqlCommand.

Related

Unable to open SQLite database file from local data store of UWP app

I'm using this section of this official MSDN tutorial: Use a SQLite database in a UWP app but I'm getting the following error:
REMARK: There are many online posts related (or similar) to this issue but none seems to have a solution. Most of these posts are a few years old so I thought this issue would have been resolved by now. Moreover, the above mentioned tutorial is using .NET Standard Class library project, as well. And the online posts regarding the issue do not have .NET Standard involved. So, I was wondering if the issue is caused by the use of .NET Standard library. Regardless, a solution will be greatly appreciated.
SQLite Error 14: 'unable to open database file'
Error occurs at line db.Open() of this code:
public static void InitializeDatabase()
{
using (SqliteConnection db =
new SqliteConnection("Filename=sqliteSample.db"))
{
db.Open();
String tableCommand = "CREATE TABLE IF NOT " +
"EXISTS MyTable (Primary_Key INTEGER PRIMARY KEY, " +
"Text_Entry NVARCHAR(2048) NULL)";
SqliteCommand createTable = new SqliteCommand(tableCommand, db);
createTable.ExecuteReader();
}
}
NOTES:
The line just below the above code reads: This code creates the SQLite database and stores it in the application's local data store. That means the app should have access to that local data store.
I'm using latest version 16.3.5 of VS2019 on Windows 10. The target version on the project is selected as Windows 10 1903 and min version as Windows 10 1903
UPDATE
This similar official 3 years old sample works fine. So, the problem seems to be related to newer versions of .NET Core. But I need to use latest version of .NET Core for other features my app is using that are not available in the older versions.
I also tried this similar old tutorial, but it did not on new version of .NET Core work either - giving exact same error.
The old problem reported in 2016 here to Microsoft seems to have resurfaced again with the new version of .NET Core.
This is a misunderstanding, SqliteConnection db = new SqliteConnection("Filename=sqliteSample.db") can not create a Sqlite file, but access the existing Sqlite database file through the path.
So you need to create a valid sqliteSample.db file and place it in the root directory of the UWP project. Select the content in the Properties -> Build operation to ensure it will be loaded into the application directory.
Update
Please create the sqliteSample.db file in LocalFolder first.
await ApplicationData.Current.LocalFolder.CreateFileAsync("sqliteSample.db", CreationCollisionOption.OpenIfExists);
Then use the path to access the database file
string path = Path.Combine(ApplicationData.Current.LocalFolder.Path, "sqliteSample.db");
using (SqliteConnection db =
new SqliteConnection($"Filename={path}"))
{
// ...
}
Best regards.

How to add AOT objects by x++ code on D365 FO

I have a question about adding AOT objects by X++ Code on D365 FO.
The goal, is to automate creation of security duty, via x++ code, instead of doing it manually
I'm trying actually with the Following code,
public static void main (Args _args)
{
#AOT
str objectName = 'MySpecTable' ;
TreeNode nodePath = TreeNode::findNode(#TablesPath);
TreeNode nodePath1;
nodePath1 = nodePath.AOTfindChild(objectName);
if(nodePath)
{
nodePath.AOTadd(objectName);
//nodePath.AOTsave();
info("Sec privilege well added");
}
else
{
nodePath.AOTadd(objectName);
nodePath.AOTsave();
info("Table well added");
}
}
But i receive the Following error,
is there any way to achieve this goal.to be able adding them via code.
Thanks
This is not possible anymore as, compared with previous AX versions, where code and metadata was dynamically interpreted in runtime, F&O executes only pre-compiled assemblies (like any other .NET application). Same way you can't create a C# class on a running .NET assembly, you can't do it either in Finance and Operations application.
Required Security artifacts must be properly created in Visual Studio, compiled and deployed to the runtime environment (UAT, PROD or whatever), and then the security configuration itself (linking these artifacts between them or with users) is now stored in the database, so it can be done directly in the Security setup forms. It can also be exported and imported with Data entities within the standard form.
What you can do is create a Visual Studio extension to automatically create such objects, so then they can be compiled and deployed correctly.

Entity Framework migration: access sql file within ASP.NET

I have a ASP.NET Web API project. I'm using Entity Framework Migrations. Currently, I have a custom script that is to be executed during a migration. I'm using the SqlFile method for this:
SqlFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Migrations/Scripts/MyCustomScript.sql"));
This works fine in the integration tests, IF I set the "Copy to Output Directory" of the script to "Copy always".
However, when running the website, the script is copied to <websiteroot>\bin\Migrations\MyCustomScript.sql, while AppDomain.CurrentDomain.BaseDirectory points to the websiteroot. Therefore, an error is thrown stating that the script cannot be found: it resides in the bin folder, not in the root.
How can I load the script so that things work both in the tests and in the actual website?
I would include the script in you dll and than load the script from the dll directly. Than you do not need any if statements and you always know you have the correct scripts included. Set the build action to Embedded resource. Then you can get the script like:
Assembly assembly = Assembly.LoadFile(dll);
using (Stream stream = assembly.GetManifestResourceStream(resourcepath))
using (StreamReader reader = new StreamReader(stream))
{
string script = reader.ReadToEnd();
I would fix it this way (it's not the best way, but it's a way)
string sqlfilepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Migrations/Scripts/MyCustomScript.sql");
if (!File.Exists(sqlfilepath))
sqlfilepath = "your other path where it might exist";

Enterprise Library not logging in setup project

I need your opinion on this: Is it possible to use enterprise library logging dll in the setup project?
Here's what I did:
I created a setup project which will call a windows form to install the database. When I installed the project, it did call the windows form. However, when I click on the "Install" button, it seems that there's a problem and I don't know where it is. Then another popup message is displayed which said that it cannot locate the logging configuration.
But the config file for the windows form is there which includes the configuration for the logging dll. I don't have any idea where to look into.
Please help me with this?
Below is the error message:
UPDATE
I observed that when I run the exe file as is, the enterprise library logging config works. But with the setup project, it does not look for it. Any help on this?
Below is the code for this:
[RunInstaller(true)]
public partial class IPWInstaller : Installer
{
public IPWInstaller()
{
InitializeComponent();
}
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
string targetPath = Context.Parameters["TargetDir"];
InstallDatabase db = new InstallDatabase(targetPath);
DialogResult dbResult = db.ShowDialog();
if (dbResult != DialogResult.OK)
{
throw new InstallException("Database is not installed.");
}
ConfigureFiles config = new ConfigureFiles(targetPath);
DialogResult configResult = config.ShowDialog();
if (configResult != DialogResult.OK)
{
throw new InstallException("Config files are not saved correctly.");
}
}
}
LATEST UPDATE:
I tried to set the value of a certain configuration to my messagebox. This is the result of it when I run the install project.
Is there a way to call my app.config in the setup project
There are at least a couple of things that can go wrong.
The app is not running as it would if you ran it as an interactive user. It is being called from an msiexec.exe process that knows nothing about your intended environment, such as working directory. None of the automatic things that happen because you run from an explorer shell will happen. Any paths you use need to be full and explicit. I think you may need to explicitly load your settings file.
Something else that can happen in a per machine install is that custom actions run with the system account so any code which assumes you have access to databases, user profile items like folders can fail.
Another problem is that Windows Forms often don't work well when called from a VS custom action. It's not something that works very well because that environment is not the STA threading model that is required for window messages etc.
In general it's better to run these config programs after the install the first time the app starts because then you are in a normal environment, debugging and testing is straightforward, and if the db gets lost the user could run the program again to recreate it instead of uninstalling and reinstalling the setup.

How to reference PowerShell Module within ASP.NET Site

I'm trying to figure out how to use the Microsoft Online Services Migration Toolkit PowerShell Commands from within an ASP.NET website (using vb.NET).
I've started off using a guide on how to use PowerShell in ASP.NET - from here: http://devinfra-us.blogspot.com/2011/02/using-powershell-20-from-aspnet-part-1.html
I'm trying to work out how to implement the Online Services Migration Toolkit PowerShell cmdlets.
Here is a snippet from my code-behind:
Sub GetUsers()
Dim iss As InitialSessionState = InitialSessionState.CreateDefault()
iss.ImportPSModule(New String() {"MSOnline"})
Using myRunSpace As Runspace = RunspaceFactory.CreateRunspace(iss)
myRunSpace.Open()
' Execute the Get-CsTrustedApplication cmdlet.
Using powershell As System.Management.Automation.PowerShell = System.Management.Automation.PowerShell.Create()
powershell.Runspace = myRunSpace
Dim connect As New Command("Get-MSOnlineUser -Enabled")
Dim secureString As New System.Security.SecureString()
Dim myPassword As String = "ThePassword"
For Each c As Char In myPassword
secureString.AppendChar(c)
Next
connect.Parameters.Add("Credential", New PSCredential("admin#thedomain.apac.microsoftonline.com", secureString))
powershell.Commands.AddCommand(connect)
Dim results As Collection(Of PSObject) = Nothing
Dim errors As Collection(Of ErrorRecord) = Nothing
results = powershell.Invoke()
errors = powershell.Streams.[Error].ReadAll()
For Each obj As PSObject In results
Response.Write(obj.Properties("Identity").Value.ToString())
Next
End Using
End Using
End Sub
When I try to run the code via the page, I'm getting the following error
The term 'Get-MSOnlineUser -Enabled' is not recognized as the name of
a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path
is correct and try again.
So I'm guessing I haven't worked out how to import the Online Services Migration Toolkit PowerShell CmdLets. I'm also not exactly sure if the line:
iss.ImportPSModule(New String() {"MSOnline"})
Is exactly correct. Is there a way I can verify the Module name?
I'm also unsure of where and how to reference the .dll files. At the moment I have copied them to my bin folder but I can't add them as references, so how does the ImportPSModule statement know where to find them? Especially when the website is published to the final production server.
One other question, should I be using the x86 or x64 cmdlets? I'm developing on Win7 x64, but not sure if the website builds as x86 or x64? Do I need to find out what architecture the server is?
"Get-MSOnlineUser -Enabled" is not a command; "Get-MSOnlineUser" is. I'm a bit confused how you got it correct further down the script with connect.Parameters.Add("Credential", ...) but didn't do the same thing for -Enabled.
Use connect.AddArgument("Enabled") or connect.Parameters.Add("Enabled", true) and you should be good to go.

Resources