Reputation: 1325
I'm an Orchard newbie, and I have a newbie question.
I am converting an existing mvc application to Orchard, and in order to practice for the real thing, I am trying to convert the contoso university sample MVC app to Orchard to learn the basics.
I have been through creating a module for it, adding menu elements to access the app, and I have also been able to display the output from the Home\Index action, so that I know that the module is set up correctly.
Now I am trying to add the Home\About action, which will display a table that is produced from a database query.
This gives me the following error:
MSDTC on server 'DEV\SQLEXPRESS' is unavailable. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.SqlClient.SqlException: MSDTC on server 'DEV\SQLEXPRESS' is unavailable.
Source Error:
Line 17: Line 18: Line 19: @foreach (var item in Model) { Line 20: Line 21:
Source File: c:\Users\dev1\Documents\My Web Sites\Orchard CMS\Modules\ContosoUniversity\Views\Home\About.cshtml Line: 19
Source File: c:\Users\dev1\Documents\My Web Sites\Orchard CMS\Modules\ContosoUniversity\Views\Home\About.cshtml Line: 19
Now, after some googling, I understand that this has something to do with the need for suppressing ambient transactions. So I add a using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress)) to my home controller:
public class HomeController : Controller
{
private SchoolContext db = new SchoolContext();
[Themed]
public ActionResult Index()
{
ViewBag.Message = "Welcome to Contoso University!";
return View();
}
[Themed]
public ActionResult About()
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress))
{
var query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
+ "FROM Person "
+ "WHERE EnrollmentDate IS NOT NULL "
+ "GROUP BY EnrollmentDate";
var data = db.Database.SqlQuery(query);
return View(data);
}
}
However, it does not help. I have read other places to Surround your data access code with this, but as I am using entity framework, I am not explicitly opening any data connections, and hence I am not sure where to put the using statement.
Upvotes: 0
Views: 684
Reputation: 1325
Thanks to Bertrand Le Roy and Giscard Biamby for pushing me in the right direction.
I agree with Bertrand that it would make sense to add a ToList in the controller to force execution of the query, but that did not help. What I had to do was to add a suppress clause in the view like this:
<table>
<tr>
<th>
Enrollment Date
</th>
<th>
Students
</th>
</tr>
@using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress))
{
foreach (var item in Model)
{
<tr>
<td>
@String.Format("{0:d}", item.EnrollmentDate)
</td>
<td>
@item.StudentCount
</td>
</tr>
}
}
</table>
I also had to add a using statement in the top part of the view:
@model IEnumerable<ContosoUniversity.ViewModels.EnrollmentDateGroup>
@using System.Transactions
And finally, in order to be allowed to use the reference, I had to add the System.Transactions assembly in web.config:
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly ="System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</assemblies>
</compilation>
Now I don't get any errors, but I don't get any data either, but that's another issue. I am sure this is a step in the right direction.
I would wish there would be a way to do this at a higher level to avoid having to change all my views, but at least I will be able to make it work.
Upvotes: 0
Reputation: 17814
I think the problem here is that the actual execution of the query is delayed and actually does not happen within the transaction scope block. If you would just call ToList() on your SQL query, that would probably fix it. It's also good practice because you don't want the actual querying to happen in the view. What you are currently sending to the view is not data, it's a query.
Upvotes: 1
Reputation: 4619
What type is db.Database.SqlQuery()
returning? Can you include the code for your view and for the model that view is using?
From this error message it looks like data access is happening from the razor view. If this is the case, you can fix it by wrapping your foreach (var item in Model) { ...}
with a using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress)) {...}
block.
You might need to import the proper namespaces into the razor view in order for the TransactionScope stuff to work from there. If I remember correctly, I had to add <add assembly="System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
inside the <system.web> <compilation> <assemblies>
block in the Orchard.Web\web.config.
Upvotes: 0