Entity Framework migration: access sql file within ASP.NET - 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";

Related

How to save generated file temporarily in servlet based web application

I am trying to generate a XML file and save it in /WEB-INF/pages/.
Below is my code which uses a relative path:
File folder = new File("src/main/webapp/WEB-INF/pages/");
StreamResult result = new StreamResult(new File(folder, fileName));
It's working fine when running as an application on my local machine (C:\Users\userName\Desktop\Source\MyProject\src\main\webapp\WEB-INF\pages\myFile.xml).
But when deploying and running on server machine, it throws the below exception:
javax.xml.transform.TransformerException:
java.io.FileNotFoundException
C:\project\eclipse-jee-luna-R-win32-x86_64\eclipse\src\main\webapp\WEB INF\pages\myFile.xml
I tried getServletContext().getRealPath() as well, but it's returning null on my server. Can someone help?
Never use relative local disk file system paths in a Java EE web application such as new File("filename.xml"). For an in depth explanation, see also getResourceAsStream() vs FileInputStream.
Never use getRealPath() with the purpose to obtain a location to write files. For an in depth explanation, see also What does servletcontext.getRealPath("/") mean and when should I use it.
Never write files to deploy folder anyway. For an in depth explanation, see also Recommended way to save uploaded files in a servlet application.
Always write them to an external folder on a predefined absolute path.
Either hardcoded:
File folder = new File("/absolute/path/to/web/files");
File result = new File(folder, "filename.xml");
// ...
Or configured in one of many ways:
File folder = new File(System.getProperty("xml.location"));
File result = new File(folder, "filename.xml");
// ...
Or making use of container-managed temp folder:
File folder = (File) getServletContext().getAttribute(ServletContext.TEMPDIR);
File result = new File(folder, "filename.xml");
// ...
Or making use of OS-managed temp folder:
File result = File.createTempFile("filename-", ".xml");
// ...
The alternative is to use a (embedded) database or a CDN host (e.g. S3).
See also:
Recommended way to save uploaded files in a servlet application
Where to place and how to read configuration resource files in servlet based application?
Simple ways to keep data on redeployment of Java EE 7 web application
Store PDF for a limited time on app server and make it available for download
What does servletcontext.getRealPath("/") mean and when should I use it
getResourceAsStream() vs FileInputStream
just use
File relpath = new File(".\pages\");
as application cursor in default stay into web-inf folder.

File Not found in exe of wpf application

When publishing the WPF application and generate an exe, I am unable to get the files which are placed in the templates-folder. When I copy my folder and files to bin it works, or if use
string StartUpPath = AppDomain.CurrentDomain.BaseDirectory.ToString();
// var gparent = Directory.GetParent(Directory.GetParent(Directory.GetParent(StartUpPath).ToString()).ToString()).ToString();
ReportDocument reportDocument = new ReportDocument();
StreamReader reader = new StreamReader(new FileStream(StartUpPath + #"\Templates\Invoice.xaml", FileMode.Open));
This code works fine for my local, but when I generate an exe, these files are not found.
That's because your files aren't in the exe. I had the same problem recently.
It sounds like you need to handle your resources - there are several ways to go about this, and Microsoft has a full explanation here about resources, including the difference between using Linked and Embedded Resources, and links through to other great guides.
I'm assuming you're using Visual Studio, in which case this should work;
right click the file you can't access
select properties (or press ALT + ENTER)
set Build Action to be Resource
set Copy to Output Directory to be Copy if newer
save
... and you should be good to go.
I think it throws an exception because the file doesn't exist on that machine. You can set Build Action to Content and Copy to Output Directory to Copy Always or Copy If Newer on property window.
These settings will make sure that you have the file to your output.

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.

EF 4.1 Code First Initialization - Alternative

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.

Assembly.GetExecutingAssembly() not looking in the correct path

I'm reading an embedded xml file using
C#:
var AssemblyRef = Assembly.GetExecutingAssembly();
TextReader reader = new StreamReader(AssemblyRef.GetManifestResourceStream("Text.xml"));
It has been working for some time, but starting throwing errors. I traced the path that it is looking for and it is looking for the dll in the root of the bin folder and not in the Debug or release folder.
Once it is published this is fine, but for local development I cannot get my one feature to work.
I have it set to Debug when compiling. Any help would be great.
You have:
Changed Assembly Name OR
Changed namespace OR
Moved the resource to a folder in the project
I changed the call to this and everything is fine.
TextReader reader = new StreamReader(Assembly.GetExecutingAssembly().AssemblyRef.GetManifestResourceStream("Text.xml"));
Making the call one statement made it work. I'm not sure why.

Resources