Problem with Unit testing of ASP.NET project (NullReferenceException when running the test) - asp.net

I'm trying to create a bunch of MS visual studio unit tests for my n-tiered web app but for some reason I can't run those tests and I get the following error -
"Object reference not set to an
instance of an object"
What I'm trying to do is testing of my data access layer where I use LINQ data context class to execute a certain function and return a result,however during the debugging process I found out that all the tests fail as soon as they get to the LINQ data context class and it has something to do with the connection string but I cant figure out what is the problem.
The debugging of tests fails here(the second line):
public EICDataClassesDataContext() :
base(global::System.Configuration.ConfigurationManager.ConnectionStrings["EICDatabaseConnectionString"].ConnectionString, mappingSource)
{
OnCreated();
}
And my test is as follows:
TestMethod()]
public void OnGetCustomerIDTest()
{
FrontLineStaffDataAccess target = new FrontLineStaffDataAccess(); // TODO: Initialize to an appropriate value
string regNo = "jonh"; // TODO: Initialize to an appropriate value
int expected = 10; // TODO: Initialize to an appropriate value
int actual;
actual = target.OnGetCustomerID(regNo);
Assert.AreEqual(expected, actual);
}
The method which I call from DAL is:
public int OnGetCustomerID(string regNo)
{
using (LINQDataAccess.EICDataClassesDataContext dataContext = new LINQDataAccess.EICDataClassesDataContext())
{
IEnumerable<LINQDataAccess.GetCustomerIDResult> sProcCustomerIDResult = dataContext.GetCustomerID(regNo);
int customerID = sProcCustomerIDResult.First().CustomerID;
return customerID;
}
}
So basically everything fails after it reaches the 1st line of DA layer method and when it tries to instantiate the LINQ data access class...
I've spent around 10 hours trying to troubleshoot the problem but no result...I would really appreciate any help!
UPDATE:
Finally I've fixed this!!!!:) I dont know why but for some reasons in the app.config file the connection to my database was as follows:
AttachDbFilename=|DataDirectory|\EICDatabase.MDF
So what I did is I just changed the path and instead of |DataDirectory| I put the actual path where my MDF file sits,i.e
C:\Users\1\Documents\Visual Studio 2008\Projects\EICWebSystem\EICWebSystem\App_Data\EICDatabase.mdf
After I had done that it worked out!But still it's a bit not clear what was the problem...probably incorrect path to the database?My web.config of ASP.NET project contains the |DataDirectory|\EICDatabase.MDF path though..

Is LINQDataAccess.EICDataClassesDataContext looking to the web.config or some other outside source of data for its setup?
I can tell you for a fact that you must jump thru hoops to get web.config accessible to your test code.
Update
Ah, yes. I see that you're using ConfigurationManager on the line where your test fails... ConfigurationManager looks to web.config for configuration. This has been a sticking point for me when I write my tests.
You need to either change the code so that the class can be instantiated without web.config, or you need to make it so that your tests can access web.config.

Does your test project have it's own configuration file? This type of behavior usually means the app can't find the connection string. Test projects require their own file since they are not running in the context of the client app.
UPDATE The error you describe after adding an app.config is common when testing web applications built on SQLExpress and attaching an .mdf. SQLExpress cannot be run in more than one process at a time. So if you have previously run your web application it may still be active and will conflict with the attempt to attach the database.
You can use SQL Management Studio to attach the database permanently and then use a more traditional connection string like:
Server=myServer;Database=EICDatabase;Trusted_Connection=True;

For me it seems like your problem is the connection string, which is not set.
I assume your unit test is in a different project than the DAL.
You call the 'new' command on the datacontext constructor without a connection string. So it should usually use its default, when set. But since this setting normally is stored in the web.config of the other project there is no connection string set and you get the error.
If its right, what i assume, you have to get the settings from the DAL project into the unit-testing project. Simplest solution should be to copy web.config connection string to app.config of unit test project.
There are other possibilities for sure, but i think its not easy to get the web.config configuration into your unit-testing project.

Related

EntityException: The underlying provider failed on Open. Can one server closing a db connection, make another server fail on opening?

I am experiencing database connection errors with an ASP.NET application written in VB, running on three IIS servers. The underlying database is MS Access, which is on a shared network device. It uses Entity Framework, code first implementation and JetEntityFrameworkProvider.
The application is running stable. But, approximately 1 out of 1000 attempts to open the database connection fails with either one of the following two errors:
06:33:50 DbContext "Failed to open connection at 2/12/2020 6:33:50 AM +00:00 with error:
Cannot open database ''. It may not be a database that your application recognizes, or the file may be corrupt.
Or
14:04:39 DbContext "Failed to open connection at 2/13/2020 2:04:39 PM +00:00 with error:
Could not use ''; file already in use.
One second later, with refreshing (F5), the error is gone and it works again.
Details about the environment and used code.
Connection String
<add name="DbContext" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=x:\thedatabase.mdb;Jet OLEDB:Database Password=xx;OLE DB Services=-4;" providerName="JetEntityFrameworkProvider" />
DbContext management
The application uses public property to access DbContext. DbContext is kept in the HttpContext.Current.Items collection for the lifetime of the request, and is disposed at it’s end.
Public Shared ReadOnly Property Instance() As DbContext
Get
SyncLock obj
If Not HttpContext.Current.Items.Contains("DbContext") Then
HttpContext.Current.Items.Item("DbContext") = New DbContext()
End If
Return HttpContext.Current.Items.Item("DbContext")
End SyncLock
End Get
End Property
BasePage inits and disposes the DbContext.
Protected Overrides Sub OnInit(e As EventArgs)
MyBase.OnInit(e)
DbContext = Data.DbContext.Instance
...
End Sub
Protected Overrides Sub OnUnload(e As EventArgs)
MyBase.OnUnload(e)
If DbContext IsNot Nothing Then DbContext.Dispose()
End Sub
What I have tried
Many of the questions on SO which address above error messages, deal with generally not being able to establish a connection to the database – they can’t connect at all. That’s different with this case. Connection works 99,99% of the time.
Besides that, I have checked:
Permissions: Full access is granted for share where .mdb (database) and .ldb (locking file) resides.
Network connection: there are no connection issues to the shared device; it’s a Gigabit LAN connection
Maximum number of 255 concurrent connections is not reached
Maximum size of database not exceeded (db has only 5 MB)
Changed the compile option from “Any CPU” to “x86” as suggested in this MS Dev-Net post
Quote: I was getting the same "Cannot open database ''" error, but completely randomly (it seemed). The MDB file was less than 1Mb, so no issue with a 2Gb limit as mentioned a lot with this error.
It worked 100% on 32 bit versions of windows, but I discovered that the issues were on 64 bit installations.
The app was being compiled as "Any CPU".
I changed the compile option from "Any CPU" to "x86" and the problem has disappeared.
Nothing helped so far.
To gather more information, I attached an Nlog logger to the DbContext which writes all database actions and queries to a log file.
Shared Log As Logger = LogManager.GetLogger("DbContext")
Me.Database.Log = Sub(s) Log.Debug(s)
Investigating the logs I figured out that when one of the above errors occured on one server, another one of the servers (3 in total) has closed the db connection at exactly the same time.
Here two examples which correspond to the above errors:
06:33:50 DbContext "Closed connection at 2/12/2020 6:33:50 AM +00:00
14:04:39 DbContext "Closed connection at 2/13/2020 2:04:39 PM +00:00
Assumption
When all connections of a DbContext have been closed, the according record is removed from the .ldb lock file. When a connection to the db is being opened, a record will be added to the lock file. When these two events occur at the exact same time, from two different servers, there is a write conflict to the .ldb lock file, which results in on of the errors from above.
Question
Can anyone confirm or prove this wrong? Has anyone experienced this behaviour? Maybe I am missing something else. I’d appreciate your input and experience on this.
If my assumption is true, a solution could be to use a helper class for accessing db, which catches and handles this error, waiting for a minimal time period and trying again.
But this feels kind of wrong. So I am also open to suggestions for a “proper” solution.
EDIT: The "proper" solution would be using a DBMS Server (as stated in the comments below). I'm aware of this. For now, I have to deal with this design mistake without being responsible for it. Also, I can't change it in the short run.
I write this as an aswer because of space but this is not really an answer.
It's for sure an OleDb provider issue.
I think that is a sharing issue.
You could do some tries:
use a newer OleDb provider instead of Microsoft.Jet.OLEDB.4.0. (if you have try 64 bits you could already have try another provider because Jet.OLEDB.4.0 is 32 bits only)
Implement a retry mechanism on the new DbContext()
Reading your tests this is probaly not your case. I THINK that Dispose does not always work properly on Jet.OLEDB.4.0 connections. I noted it on tests and I solved it using a different testing engine. Before giving up I used this piece of code
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
As you can understand reading this code, they are tries and the latest solution was changing the testing engine.
If your app is not too busy you could try to lock the db using a different mechanism (for example using a lock file). This is not really different from new DbContext() retries.
In late '90s I remember I had an issue related to disk sharing OS (I were using Novel Netware). Actually I have not experience in using mdb files on a network share. You could try to move the mdb on a folder shared with Windows
Actually I use Access databases only for tests. If you really need to use a single file database you could try other solutions: SQL Lite (you need a library, also this written by me, to apply code first https://www.nuget.org/packages/System.Data.SQLite.EF6.Migrations/ ) or SQL Server CE
Use a DBMS Server. This is for sure the best solution. As the writer of JetEntityFrameworkProvider I think that single file databases are great for single user apps (for this apps I suggest SQL Lite), for tests (I think that for tests JetEntityFrameworkProvider is great), for transfering data or, also, for readonly applications. In other cases use a DBMS Server. As you know, with EF, you can change from JetEntityFrameworkProvider to SQL Server or to MySql without effort.
You went wrong at the design stage: The MS Access database engine is unfit for ASP.Net sites, and this is explicitly stated on multiple places, e.g. the official download page under details.
The Access Database Engine 2016 Redistributable is not intended .... To be used by ... a program called from server-side web application such as ASP.NET
If you really have to work with an Access database, you can run a helper class that retries in case of common errors. But I don't recommend it.
The proper solution here is using a different RDBMS which exhibits stateless behavior. I recommend SQL Server Express, which has limitations, but if you exceed those you will be far beyond what Access supports, and wont cause errors like this.

Create Database If Not Exist Without Restarting Application

I am creating dynamic connection strings in my project. They're created on the fly with the information provided specifically for every user. When the application first fires off, if a database doesn't exist (first time user logs on), a new database is created without problems with this initializer:
public DataContext() : base()
{
// ProxyCreation and LazyLoading doesn't affect the situation so
// comments may be removed
//this.Configuration.LazyLoadingEnabled = false;
//this.Configuration.ProxyCreationEnabled = false;
string conStr = GetDb();
this.Database.Connection.ConnectionString = conStr;
}
The problem is, with this method, I have to restart the application pool on the server and the new user should be the first accessor to the application.
I need the same thing without a requirement of restarting the app. Is that possible?
(This is a SPA using AngularJS on MVC views and WebApi as data provider - May be relevant somehow, so thought I should mention)
I already tried this, but this creates an error for EF and the application doesn't start at all...
You could try a little bit different approach to connect directly (and create) the right database.
public class DataContext : DbContext
{
public DataContext(DbConnection connection) : base(connection, true) { }
}
Here you create the DbContext already with the right connection.
Take also care because you need to specify to migrations that the right connection should be used (not the Web.Config connection but the connection that raised the database creation).
See the second overload here https://msdn.microsoft.com/en-US/library/hh829099(v=vs.113).aspx#M:System.Data.Entity.MigrateDatabaseToLatestVersion.

COM Exception for client-side object called by Classic ASP page

I have tricky problem, which I'm struggling quite a bit with.
The current solution, consists of a Classic ASP site hosted on some Win2K3 server, that calls some Client-side DLL's on XP machines coded in VB6.
These client-side DLL's then again can call some other COM objects, in this particular case it calls IBM Louts Notes (Lotus Domino Objects 1.2).
Now for different reasons these DLL's has to be converted to .NET (still x86), at this stage, this is the only change to be done. This works quite well except for one piece of code which throws an error.
COMException when calling the Lotus Notes COM object
ASP script calling the DLL
Set objLotus = CreateObject("OpenLotusNotes_FU_v2.clsMain")
sRet = objLotus.OpenLotus_mail()
Client-side DLL
Dim session As NotesSession = New NotesSession() 'works well
Dim objNotesWrkSp As Object
objNotesWrkSp = Activator.CreateInstance(Type.GetTypeFromProgID("Notes.NotesUIWorkspace")) 'crashes
Exception
Retrieving the COM class factory for component with CLSID {29131502-2EED-1069-BF5D-
00DD011186B7} failed due to the following error: 80080005
Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE)).
When I try to run this code in console application on the same computer, it works. So it has to be some permissions(?), I have tried changing basically everything I can think of.
Any help would be much appreciated!
Updated 01.09.2014
What I see is when I trigger the code from ASP, is that it creates a new process of Notes everytime, but only in the background, no UI what so ever. When I trigger the code from a console application, I get the Notes UI, which asks me for password, if I don't already have notes running.
I believe that I'm getting the Exception because it eventually times out.
Have a read of this article , your dealing with an Out Of Process COM component which may not initialize properly for some reason.
Another possibility is that the COM threading model is not supported in a free threaded component which .NET is by default compiled with. You can compile you DLL with a STA attribute, but as far am I'm aware that only effects console applications. You might find some additional information in this article from MS, if you have not already read it of course. Hope something there helps you solve your problem.
Consult with your admins first, but for this scenario you can set no password for the ID the Lotus Notes uses.
I did resolve this, so if anyone else would run in to this…
First of all configure the “Notes Link” Component Service to run as a “The interactive user” and that the process owner has permissions in "Launch and Activation Permissions" and "Access permissions".
Then this should be possible
Dim objNotesWrkSp As Object
Dim objWorkspace As Type = Type.GetTypeFromProgID("Notes.NotesUIWorkspace")
objNotesWrkSp = Activator.CreateInstance(objWorkspace)
As it turned out in this particular case I could only get it to work with late-binding, when I tried to this it just opened a conhost.exe process and then never responed:
Dim session as New NotesSession
session.Initialize()
Among other similar issues... So then I only used late-binding for all communication with Notes.
Dim mailServerPath, mailFile As String
objWorkspace.InvokeMember("OpenDatabase", Reflection.BindingFlags.InvokeMethod, Nothing, objNotesWrkSp, New Object() {mailServerPath, mailFile})
And so on...

Return values from exe in javascript

i have to call an executable in the client machine in asp.net and get the return parameters, i been looking for an example but i couldn't find it.
it this possible to recover the output parameters from one exe in JavaScript?
i know that can i write:
var WshShell = new ActiveXObject("WScript.Shell");
var oExec = WshShell.Exec("My.exe");
but the clients executable returns 0 or 1 that values are the ones i need to collect
Thanks in advance
Browser-based JavaScript can't call executable files on client machines; to do so would be a catastrophic security problem. If you have to run an executable on the client machine, consider asking the user to install a .NET application, an ActiveX control, or something like Java if you want to be platform-independent.
Depending on what you're trying to do, you may not need to run an EXE on the client machine; you can do a LOT with standard cloud-type scenarios (JS or SilverLight on the client, Web services or WCF on the server). Without more information about your situation, however, it's impossible to tell.
EDIT: Based on your comments that you're using the ActiveXObject.Exec method, you can use the StdOut property of the WshScriptExec object that method returns. From MSDN's article on the StdOut property:
if (!oExec.StdOut.AtEndOfStream)
{
input += oExec.StdOut.Read(1);
//...
}

ASP.NET Connection String

I am having some trouble with one of my ASP.NET 2.0 application's connection string. There are instances that I would get a ConnectionString Property Has not Been Initialized problem which occurs randomly and intermittently and without any reason.
My Connection string is actually coming from a webservice, because different kinds of users are provided with different sets of connection string depending on their user level.
What I have done so far goes like this:
I have a master page (mstr.page) and the corresponding code behind (mstr.page.vb).
In my master page, I retrieve initially the connection string and store the same into a session variable, i.e.
Session("ConnString") = "RetrievedConnectionString"
Now in one of my pages, let us say page1.aspx.vb, I use public shared functions from a class (named MyClass.vb) and use it in my page1.aspx.vb.
Some codes for reference:
[MyClass.vb]
Imports System.Web
NameSpace ClassNameSpace
Public Class Admin
Protected Shared da as New DataAccess()
Public Shared Function MYFunction() as String
'Execute some sql statements here, using the DataAccess
stringToReturn = Ctype(da.ExecuteScalar("SQLCommand"), String)
Return stringToReturn
End Function
End Class
End NameSpace
[DataAccessClass.vb]
Public Class DataAccess()
Private m_ConStr As String = ""
Public Sub New()
m_ConStr = HttpContext.Current.Session("ConnString")
End Sub
'Some methods for SQL statement execution (ExecuteQuery, ExecuteScalar)
End Class
[Page1.aspx.vb]
Imports ClassNameSpace
Protected Sub Page_Load(....) Handles Me.Load
Dim strValue as String = Admin.MyFunction()
End Sub
I have placed the code above to show you some rough idea of how things are going.
Basically, the function Admin.MyFunction() at times fails, because in the data access class, the connection string seems to have lost it's value (either blank or Nothing).
This has troubled me for quite some time already.
I hope someone can point me in the right direction to resolve this. Basically, I want my connection string which is retrieved by each user visiting the web application be maintained across all the time and be used anywhere. Session variable does not seem to be the best fit since when the ASP.NET recycles its process, the session is lost.
By the way, I am retrieving the connectionstring initially via the master page from a web service. I tried to place the same retrieve function in the Data Access class when conditions is that the session variable is lost, but I think my application cannot connect to the Web Service during the recycle process.
Any advice would be greatly appreciated on this.
Update on this:
I tried to use Session Variable and set the mode to State Server, but apparently some DLLs which I am using cannot be serialized, thus I am back to square one.
Is there a better way to do this?
One thing to check is if your Session is getting clobbered. If your using the (default) in-memory Session, then sessions die anytime an ASP.NET worker process is recycled. If this is causing your issue, you might have to look into using the ASP.NET SessionServer in IIS, or SQL Server as your Session storage.
I'd try to limit your use of the Session for this type of thing as much as possible. If you utilize the Web.Config for storing your connection strings, you can access it at anytime and it will not expire on you like the session.
You may also consider having a static data access class if it is the same for all users for the applications instance...
This is the exact same problem I was experiencing, and it turned out to be the session variables dying so the connection string couldn't be initialized properly.
Why cant your app use just one connection string? and why does the connection string need to come in through a webservice? that adds a huge amount of latency to the entire process. I assume it probably has to do something with data security in your database.
If you have to do this, I'd say, can't you have a fall back / default connectionstring? Wrap your code that attempts to pull it out of the session with some error handeling and if it fails revert to your default?
I would place your web service and web app in different app pools. Then increase the timeout length of your web apps pool.

Resources