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.
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.
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.
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.
Related
I am new in Sharepoint. I have created customcontrol and added it to web-part. I have registered control:
<%# Register TagPrefix="UserControls" TagName="FormContactUs"
Src="~/_CONTROLTEMPLATES/FormContactUs.ascx" %>
<%# Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages"
Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<UserControls:FormContactUs runat="server" id="formContactUs" Mode="Colleague" />
But it returns error : "element 'FormContactUs' is unknown element. This can occur if there is a compilation error or the web.config file is missing "
Please any ideas where the issue can be.. Thanks!
You need to reference the usercontrol like this:
<UserControls:FormContactUs runat="server" ID="formContactUs" Mode="Colleague" />
Happy coding!
Within my DataFormWebPart I have a 'DataSourcesString' property which references and queries a list.
Depending on what page the DataFormWebPart is displayed on I need to be able to configure the query (parameterise the string 'Dispute Resolution' in the code below) within the 'DataSourcesString'.
Does anyone know if there a way to paramterise this by modifying the web part through either the XSL Editor or Paramter Editor?
The web part code snippet relating to the 'DataSourcesString' is below
<property name="DataSourcesString" type="string"><%# Register TagPrefix="sharepoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %><sharepoint:SPDataSource runat="server" DataSourceMode="List" SelectCommand="<View><Query><OrderBy><FieldRef Name="ID"/></OrderBy><Where><Eq><FieldRef Name="Primary"/><Value Type="Text">Dispute Resolution</Value></Eq></Where></Query></View>" UseInternalName="True" IncludeHidden="True" ID="datasource1">
Thanks! I appreciate this may not be so clear without screenshots..
You can do this using a QueryString parameter on the DataForm. I'm assuming you're only able to export the webpart. So, export the webpart and save the .webpart to your desktop. Open it and modify it like so:
In your DataSourcesString remove the where clause entirely:
<property name="DataSourcesString" type="string"><%# Register TagPrefix="sharepoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %><sharepoint:SPDataSource runat="server" DataSourceMode="List" SelectCommand="<View><Query><OrderBy><FieldRef Name="ID"/></OrderBy></Query></View>" UseInternalName="True" IncludeHidden="True" ID="datasource1">
In the <property name="ParameterBindings" type="string"> node, add:
<ParameterBinding Name="MyVariable" Location="QueryString(MyVar)"/>
In the XSL for the webpart itself, find <xsl:param name="dvt_partguid" /> and just below it add:
<xsl:param name="MyVar" />
Finally, find select="/dsQueryResponse/Rows/Row and modify it to be:
select="/dsQueryResponse/Rows/Row[#Primary='$MyVar']
Save the webpart, upload it back, and you should now be able to filter it by adding MyVar=Whatever to your querystring
The only way I found of manipulating parameters at run time was from C# code behind.
Here are the steps required:
Dump your DataFormWebPart code into an ascx control. (or a custom webpart if you wish).
In the code behind of the control, reference your DataFormWebPart via it's ID just like you would to any other user control such as a text box.
Use the DataFormWebPart object to fiddle with its Data Source (if required) and its queries. You can get a handle on all of its parameters.
I have a feature that automatically creates some web part pages. I want to display a list in my web part page but I can't get the list to show up. Here is my code in my element.xml file:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Path="PageTemplates" Url="" >
<File Url="Tab3.aspx" Name="Tab3.aspx" Type="Ghostable" >
<View List="Lists/Links"
BaseViewID="0"
WebPartZoneID="Left"
WebPartOrder="0"/>
</File>
</Module>
</Elements>
I know i set up the page correctly because I put the following content editor web part into the page and it shows up:
<AllUsersWebPart WebPartZoneID="Left" WebPartOrder="0">
<![CDATA[
<WebPart xmlns="http://schemas.microsoft.com/WebPart/v2"
xmlns:cewp="http://schemas.microsoft.com/WebPart/v2/ContentEditor">
<Assembly>Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
<TypeName>Microsoft.SharePoint.WebPartPages.ContentEditorWebPart</TypeName>
<Title>Some content that you want to provision with the feature</Title>
<FrameType>TitleBarOnly</FrameType>
<cewp:Content>
Hello world.
</cewp:Content>
</WebPart>
]]>
</AllUsersWebPart>
I'm getting the following error in the log: Not enough information to determine a list for module "(null)". Assuming no list for this module.
What am I doing wrong?
More details:
When I use
<View List="Lists/Links"...>
I get no error but nothing shows up on my page. if I enter a bogus list name I get the following error:
Cannot complete this action.
Please try again. at Microsoft.SharePoint.Library.SPRequestInternalClass.EnableModuleFromXml(String bstrFeatureDirectory, String bstrUrl, String bstrXML)
at Microsoft.SharePoint.Library.SPRequest.EnableModuleFromXml(String bstrFeatureDirectory, String bstrUrl, String bstrXML)
I don't believe the previous error I quoted is related to my problem. The error I posted before was
I believe I need to create a ListInstance element in elements.xml file of my feature. I added the following to the top of my file:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ListInstance
FeatureId="6A9FB262-8EAD-46C1-814B-7FED72D34EBF"
Id="Links"
Url="Links"
Title="Links"
TemplateType="103"/>
....
I get the following error:
Failed to find a suitable list for tag in module for file 'Tab3.aspx' given List attribute 'Links'.
Where is that list located? You may need to specify the web name, probably by Guid. If 'lists' is the web then once you reference this you only need the list name, i.e. 'links'
My solution was to create the page in Sharepoint Designer and then copy the code into the feature aspx page.
I have created a CustomAction feature to add a button to the "Actions" menu on a list. When I don't specify the ControlAssembly/ControlClass attributes then the button shows up. When I specify those attributes the button does not show up. I have tried adding a matching SafeControl element in the site web.config. I am using VSeWSS.
UPDATE - removed link to other question - not sure how i did that.
My question is can anyone tell me why my CustomAction button is not showing up when I specify the ControlAssembly and ControlClass attributes ?
UPDATE 2 - RegenConfigTemp actually does inherit from WebControl, sorry! My machine with web access is different from my dev machine and there is no way to move files between them short of burning a CD.
here are my files:
manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<Solution SolutionId="GUIDHERE" xmlns="http://schemas.microsoft.com/sharepoint/">
<FeatureManifests>
<FeatureManifest Location="RegenConfigTemp\feature.xml" />
</FeatureManifests>
<Assemblies>
<Assembly Location="WebFeature.dll" DeploymentTarget="GlobalAssemblyCache" />
</Assemblies>
</Solution>
feature.xml
<Feature Id="GUIDHERE" Title="RegenConfigTemp" Scope="Web" Version="1.0.0.0" Hidden="FALSE" DefaultResourceFile="core" xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="RegenConfigTemp\Module.xml" />
</ElementManifests>
</Feature>
Module.xml
<?xml version="1.0" encoding="utf-8"?>
<Elements Id="GUIDHERE" xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction
Id="GUIDHERE"
RegistrationType="List"
RegistrationId="1981"
GroupId="ActionsMenu"
Location="Microsoft.SharePoint.StandardMenu"
Sequence="1000"
Title="Regenerate List Contents"
ControlAssembly="WebFeature, Version=1.0.0.0, Culture=neutral, PublicKeyToken=myPKTokenHere"
ControlClass="WebFeature.RegenConfigTemp"
></CustomAction>
</Elements>
RegenConfigTemp.cs
using System;
using System.Runtime.InteropServices;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;
namespace WebFeature
{
[Guid("GUID HERE MATCHES 1st GUID in Module.xml")]
public class RegenConfigTemp : WebControl
{
protected override void OnLoad(EventArgs e)
{
this.EnsureChildControls();
base.OnLoad(e);
}
protected override void CreateChildControls()
{
base.CreateChildControls();
}
}
}
I added the following to the web.config
<SafeControl Assembly="WebFeature, Version=1.0.0.0, Culture=neutral, PublicKeyToken=myPKTokenHere" Namespace="WebFeature" TypeName="RegenConfigTemp" Safe="True" />
Turns out the problem was in Module.xml. I was missing the 'equals' sign after 'Version' in this (corrected) line:
ControlAssembly="WebFeature, Version=1.0.0.0, Culture=neutral, PublicKeyToken=myPKTokenHere"
I got on the right trail b/c I discovered Sharepoint's diagnostic logging, and the first comment on this blog: http://blog.lostparticles.net/?p=23 was my problem exactly.
Thanks for y'alls help.
UPDATE: I had to fix web.config line as well. I ended up putting the safecontrol line in the manifest instead of directly in the web.config; thanks JMD. (BTW, why doesn't VSeWSS do that for me, when it does for web parts?)
Are you sure that your code is supposed to render anything? Which class are you inheriting from and where is your render code? Have you checked the SharePoint log for any exception?
This is not an answer to your question, but you can place your SafeControl tag in the manifest instead of the web.config.
Surely RegenConfigTemp should be inheriting from something? At present you're not adding any controls, so if you're overriding an empty control that would be why you're not seeing anything. If nothing else, try setting a breakpoint or adding some diagnostic tracing to CreateChildControls() to see if the code is executing.
I have developed a list definition project and created a custom view aspx page to be the default view of the list. I would now like to add a custom webpart to be displayed in the custom view aspx page. Any ideas of how it can be done?
You can use a feature receiver and manage the addition of web parts during feature activation. Here is a bit of a stub to help get you started.
In the feature activated method call code similar to the following:
// Add web parts to the .aspx page that was provisioned
SPFile page = site.GetFile(<<page url>>);
Hashtable hashWebPartsOnPage = new Hashtable();
using (SPLimitedWebPartManager mgr = page.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
try
{
// First, let's clear the existing web parts off of the form
foreach (System.Web.UI.WebControls.WebParts.WebPart webPart in mgr.WebParts)
{
hashWebPartsOnPage.Add(webPart.ID, webPart);
}
foreach (string webPartName in hashWebPartsOnPage.Keys)
{
System.Web.UI.WebControls.WebParts.WebPart webPart = hashWebPartsOnPage[webPartName] as System.Web.UI.WebControls.WebParts.WebPart;
mgr.DeleteWebPart(webPart);
}
// Add Part to the proper Zone
MyWebPart myWebPart = new MyWebPart();
//set web part properties
mgr.AddWebPart(myWebPart, "FullPage", 1);
}
finally
{
mgr.Web.Dispose();
}
}
page.Update();
On SharePoint 2010 you can add a custom webpart or SharePoint WebPart in the same view definition inside the Schema.xml of the List definition (I'm not talking about List instance).
Although isn't directly explained by MSDN, and if you look at the View Schema you can't see a '<WebParts>' definition, you can actually do something like this:
<View BaseViewID="7" Type="HTML" WebPartZoneID="Main" DisplayName="$Resources:CILSS_defaultView" DefaultView="TRUE" MobileView="FALSE" MobileDefaultView="FALSE" SetupPath="pages\viewpage.aspx" ImageUrl="/_layouts/images/generic.png" Url="CI_Projects.aspx">
<Toolbar Type="Standard" />
<XslLink Default="TRUE">main_cilss.xsl</XslLink>
<RowLimit Paged="TRUE">30</RowLimit>
<ViewFields>
<FieldRef Name="Attachments"></FieldRef>
<FieldRef Name="LinkTitle"></FieldRef>
<FieldRef Name="CILSS_ProjectDescription"></FieldRef>
</ViewFields>
<Query>
<OrderBy>
<FieldRef Name="LinkTitle" Ascending="TRUE"></FieldRef>
</OrderBy>
</Query>
<ParameterBindings>
<ParameterBinding Name="NoAnnouncements" Location="Resource(wss,noXinviewofY_LIST)" />
<ParameterBinding Name="NoAnnouncementsHowTo" Location="Resource(wss,noXinviewofY_DEFAULT)" />
</ParameterBindings>
<WebParts>
<AllUsersWebPart WebPartZoneID="Main" WebPartOrder="2">
<![CDATA[<WebPart xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/WebPart/v2">
<Title>Default Home Webpart</Title>
<FrameType>None</FrameType>
<Description>Use for formatted text, tables, and images.</Description>
<IsIncluded>true</IsIncluded>
<ZoneID>Left</ZoneID>
<PartOrder>0</PartOrder>
<FrameState>Normal</FrameState>
<Height />
<Width />
<AllowRemove>true</AllowRemove>
<AllowZoneChange>true</AllowZoneChange>
<AllowMinimize>true</AllowMinimize>
<AllowConnect>true</AllowConnect>
<AllowEdit>true</AllowEdit>
<AllowHide>true</AllowHide>
<IsVisible>true</IsVisible>
<DetailLink />
<HelpLink />
<HelpMode>Modeless</HelpMode>
<Dir>Default</Dir>
<PartImageSmall />
<MissingAssembly>Cannot import this Web Part.</MissingAssembly>
<PartImageLarge>/_layouts/images/mscontl.gif</PartImageLarge>
<IsIncludedFilter />
<Assembly>Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
<TypeName>Microsoft.SharePoint.WebPartPages.ContentEditorWebPart</TypeName>
<ContentLink xmlns="" />
<Content xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor">
<Value><div>Create and view Project documents:</div>
<br/></Value></Content>
<PartStorage xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor" />
</WebPart>]]>
</AllUsersWebPart>
</WebParts>
</View>
This view definition includes a Content Editor Webpart in the list view called 'CI_Projects.aspx'
Remember to assign the WebPartZoneId and assign a BaseViewID different from the default views included in the List definition.
The webpart will provisioned on every List you will create with this List Definition. (obviously only on the named view.aspx you define).
Well i would like to access the list definition view page which i don't think will be accessible using the above site.GetFile() method. Any other options you think we can use to achieve it. I have tried the following steps:
Copy the OOB “ViewPage.aspx” and place it in the same folder as “CustomViewPage.aspx”
Create the custom web part which shows the items of the view with your custom approach.
Create a feature to provision the “CustomViewpage.aspx” along with your custom web part.
Create a custom list definition. In the schema.xml file of the definition for all the views mention the “SetupPath” to refer your “CustomViewPage.aspx”. With this step all the views mentioned in the list definition will use the “CustomViewPage.aspx” to create the view pages and as well all the views which you create after the creation of the list will use the “customViewPage.aspx” as the base page to create the view pages.
Step 1:
Just copy the OOB “ViewPage.aspx” and place it in the C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\Pages folder as “CustomViewPage.aspx”
Step 2:
Create the custom web part which shows the items of the view with your custom approach. Basically use the GetViewfromUrl(“Lists//”) method to get the view and then retrieve the items in the web part. The code snippet for the custom web part looks like follows :
SPList list = SPContext.Current.List;
String strViewName =
SPView view = SPContext.Current.Web.GetViewFromUrl("Lists/list/ "+strViewName);
SPListItemCollection listItems = list.GetItems(view);
.
.
.
.
After getting the list items then do your custom approach of displaying the items.
Build the web part DLL and place it in the GAC.
Step 3:
Create a feature to provision the “CustomViewPage.aspx” along with your custom web part. By activating this feature the “Customviewpage.aspx” will be embedded with your custom web part. The elements manifest file content looks like follows :
<File Url="Pages/CustomViewPage.aspx" Type="Ghostable">
<AllUsersWebPart WebPartZoneID="Main" WebPartOrder="1">
<![CDATA[
<WebPart xmlns="http://schemas.microsoft.com/WebPart/v2">
<Assembly>CustomWebpartforView, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e3483ddc8b0d437a</Assembly>
<TypeName> CustomWebpartforView.MyCustomview</TypeName>
<FrameType>None</FrameType>
<IsVisible>true</IsVisible>
<Title>Custom Web part for View</Title>
</WebPart>
]]>
</AllUsersWebPart>
</File>
This step gives me error for the source file path which i modified by giving the Path attribute in the File Tag
Step 4:
Now the base custom view page is available along with the web part. Now how to integrate the custom view page with the list definition. Create a custom List definition and for all the views defined in the schema mention the “SetupPath” to use the “CustomViewPage.aspx”. Now the custom view page will be used as the base view page for all the views defined in the list definition and as well the views created later also will be using the “CustomViewpage.aspx” as the base page. The sample snippet for declaring the views inside the schema.xml is as follows :
Install and activate the feature of your custom list definition.
Now with all these steps, when you create a list based on this custom list definition then all the views created will be using the “CustomViewPage.aspx” to create the view pages and your custom web part will be rendered instead of the OOB dataformwebpart. The views which you will be creating after the creation of the List (Through UI, Through Object Model) will also use the “CustomViewpage.aspx” as the base page to create view pages.
For some reason i am still unable to see the CustomViewPage.aspx with my custom webpart. Am i missing somthing or there is something missing in this article.