Deploy BrowserFormWebPart declaratively without BinarySerializedWebPart Element - sharepoint-2010

Does anyone know if there is a way to deploy a BrowserFormWebPart (custom InfoPath form for a list content type) using standard AllUsersWebPart element and a CDATA section for the properties? So far I have tried without success. Any help is appreciated.

After 2 days of research - Following code works
private void UpdateInfoPathForms(SPSite oSite)
{
UpdateInfoPath(oSite, "Lists/Audit Calendar/Item/newifs.aspx");
UpdateInfoPath(oSite, "Lists/Audit Calendar/Item/displayifs.aspx");
UpdateInfoPath(oSite, "Lists/Audit Calendar/Item/editifs.aspx");
}
private void UpdateInfoPath(SPSite oSite, string formFileLocation)
{
var file = oSite.RootWeb.GetFile(formFileLocation);
using (SPLimitedWebPartManager manager = file.GetLimitedWebPartManager(System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared))
{
try
{
var wp1 = new Microsoft.Office.InfoPath.Server.Controls.WebUI.BrowserFormWebPart();
wp1.SubmitBehavior = Microsoft.Office.InfoPath.Server.Controls.WebUI.SubmitBehavior.FormDefault;
wp1.FormLocation = "~list/Item/template.xsn";
wp1.ContentTypeId = oSite.RootWeb.Lists["Audit Calendar"].ContentTypes["Item"].Id.ToString();
IListWebPart listWebpart = wp1 as IListWebPart;
listWebpart.ListId = oSite.RootWeb.Lists["Audit Calendar"].ID;
if (formFileLocation.Contains("newifs.aspx"))
{
listWebpart.PageType = PAGETYPE.PAGE_NEWFORM;
}
else if (formFileLocation.Contains("displayifs.aspx"))
{
wp1.ListFormMode = Microsoft.Office.InfoPath.Server.Controls.WebUI.ListFormMode.ReadOnly;
listWebpart.PageType = PAGETYPE.PAGE_DISPLAYFORM;
}
else if (formFileLocation.Contains("editifs.aspx"))
{
listWebpart.PageType = PAGETYPE.PAGE_EDITFORM;
}
listWebpart.ViewFlags = SPViewFlags.None;
manager.AddWebPart(wp1, "Main", 0);
manager.SaveChanges(wp1);
}
finally
{
manager.Web.Dispose();
}
}

I have had the same problem. Here is what I tried:
<AllUsersWebPart WebPartZoneID="Main" WebPartOrder="2">
<![CDATA[
<webParts>
<webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
<metaData>
<type name="Microsoft.Office.InfoPath.Server.Controls.WebUI.BrowserFormWebPart, Microsoft.Office.InfoPath.Server, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<importErrorMessage>Cannot import this Web Part.</importErrorMessage>
</metaData>
<data>
<properties>
<property name="ChromeType" type="chrometype">None</property>
<property name="HelpMode" type="helpmode">Modeless</property>
<property name="ChromeState" type="chromestate">Normal</property>
</properties>
</data>
</webPart>
</webParts>]]>
</AllUsersWebPart>
I then have a Feature Receiver that configures the web part:
using (SPLimitedWebPartManager manager = file.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
try
{
BrowserFormWebPart webpart = GetWebPart(manager);
webpart.SubmitBehavior = SubmitBehavior.FormDefault;
webpart.FormLocation = "~list/MyList/template.xsn";
webpart.ContentTypeId = "0x01003C8AD6E14DAD5342BBFAA84E63F8022C";
manager.SaveChanges(webpart);
}
finally
{
manager.Web.Dispose();
}
}
The BrowserFormWebPart properties are required for getting the form to display, but for some reason, setting those properties in the AllUsersWebPart section did not work. The form displays and I can fill it out, but the values from the form do not get inserted into the fields of the list item. I added the following section to the Feature Receiver to try to get the form to tie into the fields of the list item:
IListWebPart listWebpart = webpart as IListWebPart;
listWebpart.PageType = PAGETYPE.PAGE_EDITFORM;
listWebpart.ViewFlags = SPViewFlags.None;
Unfortunately, no joy. And that is as far as I got. Hopefully you'll have better luck.

Related

why it is showing project name as "Default" in sitefinity dashboard portal once I run it

I am new to Sitefinity. But I followed steps from tutorial and created the one project named as "SFcmsDemo" and when I run this project and Sitefinity dashboard appears on localhost it is showing name as "Default" instead of "SFcmsDemo", The tutorial I read is showing the correct name in that but when I tried it is showing as "Default". Can anyone please help me find out the root cause and solution for this. I am attaching some screenshot which will help to understand more. Thanks.
Default can be easily changed if you click on it and then Manage Site.
UPDATE
From the decompiled Telerik.Sitefinity.dll (v.12.2):
internal static Site GetOrCreateDefaultSite()
{
Site site;
string str = "CreateDefaultSite";
MultisiteManager manager = MultisiteManager.GetManager(null, str);
using (ElevatedModeRegion elevatedModeRegion = new ElevatedModeRegion(manager))
{
ProjectConfig projectConfig = Config.Get<ProjectConfig>();
Guid siteMapRootNodeId = projectConfig.DefaultSite.SiteMapRootNodeId;
Site site = (
from s in manager.GetSites()
where s.SiteMapRootNodeId == siteMapRootNodeId
select s).FirstOrDefault<Site>();
if (site == null)
{
site = (projectConfig.DefaultSite.Id == Guid.Empty ? manager.CreateSite() : manager.CreateSite(projectConfig.DefaultSite.Id));
site.IsDefault = true;
site.IsOffline = false;
site.site = projectConfig.DefaultSite.site;
site.SiteMapRootNodeId = siteMapRootNodeId;
site.Name = (projectConfig.ProjectName != "/" ? projectConfig.ProjectName : "Default");
....
Note in the last line how it looks in the projectConfig.ProjectName value and if it is equal to "/" then it sets it to "Default"
Now, if we look at the ProjectConfig there is this:
[Browsable(false)]
[ConfigurationProperty("projectName", DefaultValue="/")]
[ObjectInfo(typeof(ConfigDescriptions), Title="ProjectNameTitle", Description="ProjectNameDescription")]
public string ProjectName
{
get
{
return (string)this["projectName"];
}
internal set
{
this["projectName"] = value;
}
}
So, default value is indeed "/", so that's why when the site is created it has a name of Default.

Web Deploy API and Web Management Service (WMSVC)

I'm trying to translate the following WORKING command line into web deploy api (Microsoft.Web.Deployment) code:
"C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe" -verb:sync -source:contentPath="\\myserver\code_to_deploy" -dest:contentPath="Default Web Site",wmsvc="mysandbox",userName="MyWebDeployUser",password="MyPassword" -allowUntrusted
My looks like this:
string srcPath = "\\myserver\code_to_deploy";
string destPath = "Default Web Site";
DeploymentBaseOptions sourceOptions = new DeploymentBaseOptions();
sourceOptions.TraceLevel = TraceLevel.Verbose;
sourceOptions.Trace += new EventHandler<DeploymentTraceEventArgs>(Src_Trace);
DeploymentBaseOptions destOptions = new DeploymentBaseOptions();
destOptions.UserName = "MyWebDeployUser";
destOptions.Password = "MyPassword";
destOptions.AddDefaultProviderSetting("contentPath", "wmsvc", "mysandbox");
destOptions.AuthenticationType = "basic";
destOptions.TraceLevel = TraceLevel.Verbose;
destOptions.Trace += new EventHandler<DeploymentTraceEventArgs>(Dest_Trace);
ServicePointManager.ServerCertificateValidationCallback = (s, c, chain, err) =>
{
return true;
};
DeploymentSyncOptions syncOptions = new DeploymentSyncOptions();
syncOptions.DeleteDestination = true;
using (DeploymentObject depObj = DeploymentManager.CreateObject(DeploymentWellKnownProvider.ContentPath, srcPath, sourceOptions))
{
var summary = depObj.SyncTo(DeploymentWellKnownProvider.IisApp, destPath, destOptions, syncOptions);
}
When the code makes the call to 'AddDefaultProviderSetting' it fails saying that wmsvc is not supported by the provider. If I remove the line I receive a 401 from the server. Any examples of doing this or other help is much appreciated.
I don't know whether you have found a solution but here is a code snippet that allows to use wmsvc for those who need it:
DeploymentBaseOptions destinationOptions = new DeploymentBaseOptions()
{
UserName = "<user_name>",
Password = "<password>",
IncludeAcls = false,
AuthenticationType = "Basic",
UseDelegation = true,
ComputerName = "https://<server>:8172/msdeploy.axd?Site=<website>"
};
// Use -allowUntrusted option
ServicePointManager.ServerCertificateValidationCallback +=
new RemoteCertificateValidationCallback(
(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => { return true; });
string package = <zip_package_fullPath>;
string parameters = <project_SetParameters_xml_fullPath>;
using (var deploymentObject = DeploymentManager.CreateObject(DeploymentWellKnownProvider.Package, package))
{
deploymentObject.SyncParameters.Load(parameters);
DeploymentSyncOptions syncOptions = new DeploymentSyncOptions();
DeploymentChangeSummary results = deploymentObject.SyncTo(destinationOptions, syncOptions);
}
It's quite hard to find documentation on these topics. Btw, I've not succeeded in using AddDefaultProviderSetting, even by creating a .exe.configSettings file and I'm not sure it's the right method to achieve what you want to.
To create a virtual application instead of a website, only .SetParameters.xml has to be changed from
<setParameter name="IIS Web Application Name" value="<WebSite>" />
to
<setParameter name="IIS Web Application Name" value="<WebSite>/<VirtualApp>" />
Hope this helps.

[Zend_Form][1.11.1] Error Message Fatal error: Class 'Admin_Form_Login' not found in ...\modules\default\controllers\IndexController.php

I don't speak english fluently (i'm french) so i will be
i followed the tutorial here and i got this structure
Application
--Modules
------admin
---------controller
---------views
------etat
---------controller
---------views
------default
---------controller
---------views
--configs
bootstrap.php
My problem is that, when i created my first form and tried to view it in my browser, i got the following error:
Fatal error: Class 'Admin_Form_Login' not found in C:\wamp\www\get\application\modules\default\controllers\IndexController.php on line 14.
Here is my code:
My controller : /modules/etat/controller/IndexController.php
class Etat_IndexController extends Zend_Controller_Action
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
// action body
$form = new Etat_Form_InfoAgent();
$this->view->form = $form;
}
}
My form : /modules/etat/forms/InfoAgent.php
class Etat_Form_InfoAgent extends Zend_Form
{
public function init()
{
/* Form Elements & Other Definitions Here ... */
$this->setName('infoagent');
$this->setMethod('post');
$login = new Zend_Form_Element_Text('matricule');
$login->setLabel('Matricule:');
$login->setRequired(true);
$login->addFilter('StripTags');
$login->addFilter('StringTrim');
$this->addElement($login);
$password = new Zend_Form_Element_Password('agence');
$password->setLabel('Code agence:');
$password->setRequired(true);
$password->addFilter('StripTags');
$password->addFilter('StringTrim');
$this->addElement($password);
$submit = new Zend_Form_Element_Submit('submit');
$submit->setLabel('Valider');
//$submit->style = array('float: right');
$this->addElement($submit);
}
}
My view : /modules/etat/view/script/index.phtml
<br /><br />
<div id="view-content">
<?php echo $this->form; ?>
</div>
Configuration file : configs/application.ini
[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
appnamespace = "Application"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.frontController.params.displayExceptions = 0
;Modular structure
resources.modules[] =
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.frontController.params.prefixDefaultModule = "1"
;database ressources
resources.db.adapter = PDO_MYSQL
resources.db.params.host = localhost
resources.db.params.username = root
resources.db.params.password =
resources.db.params.dbname = bd_test
[staging : production]
[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1
I have searched the web for solution but i didn't get it. I saw a post about the same problem on your website (stackoverflow) and i tried to aplly your instructions without solving my problem.
i precise that i haven't change the code on my bootstrap and my public/index.php file
I hope you could help me soon.
thx
Make sure you have created a Bootstrap.php in each module directory, which looks like:
class Admin_Bootstrap extends Zend_Application_Module_Bootstrap
{}
In which Admin is the name of the module.
Also, make sure there is actually a file Login.php inside directory modules/admin/forms with a class Admin_Form_Login

Approve a SharePoint workflow task using SharePoint Web Services / Object Model

I have created a workflow is SharePoint Designer and associated it with a list. The workflow creates an approval process, so SharePoint creates a task in the Tasks list so that the user can approve or reject.
What I need to do is to approve or reject the task without opening the task in the task list. After some research I figured that I can use SharePoint Web Services. However I feel lost as I don't know which service, e.g. Lists.asmx, and which method, e.g. UpdateListItems, to call.
Can someone guide me through the following:
1- Is it feasible to approve a workflow task SharePoint Web Services?
2- Can you show me an example of how to approve a task, e.g. which service and method to call and what should be the parameters?
Update
I have been using the following XML to set the workflow to complete:
batchElement.InnerXml = "<Method ID='1' Cmd='Update'>" // Also used Moderate
+ "<Field Name='ID'>115</Field>"
+ "<Field Name='Status'>Completed</Field>"
+ "<Field Name='FormData'>Completed</Field>" // Also used Approved
+ "<Field Name='WorkflowOutcome'>Approved</Field>"
+ "<Field Name='Completed'>True</Field>"
+ "<Field Name='PercentComplete'>1</Field>"
+ "<Field Name='_ModerationStatus'>0</Field>"
+ "</Method>";
The task list item is updated but the WorkflowOutcome remains empty and the workflow doesn't move to the next step.
What else I am missing?
Update #2
I am suspecting the ExtendedProperties of the task list item. For an item that was completed using the UI, the ExtendedProperties shows ws_TaskStatus='Approved'. However for an item that was approved using the code ws_TaskStatus doesn't exist.
Update #3
From an MSDN post, I was told to use the Workflow.asmx instead of the Lists.asmx.
I have used the following code:
WorkflowService.Workflow listProxy = new WorkflowService.Workflow();
listProxy.Url = "http://<server_name>/_vti_bin/workflow.asmx";
listProxy.UseDefaultCredentials = true;
int todoID = 118;
Guid tasklistID = new Guid("{79ABFDE7-0398-4AD7-918A-0D40204E7726}");
string itemURL = "http://<server_name>/TestLibrary/volshext.log";
XmlDocument taskData = new XmlDocument();
taskData.Load(#"..\..\TaskData.xml");
try
{
XmlNode response = listProxy.AlterToDo(itemURL, todoID, tasklistID, taskData.DocumentElement);
Console.WriteLine(response.InnerText);
}
The XML I am using to approve the task is
<my:myFields xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD" >
<my:TaskStatus>#</my:TaskStatus>
<my:Comments />
<my:DelegateTo />
<my:NewDescription>Please approve Workflow Demo</my:NewDescription>
<my:NewDueDate />
<my:RequestTo />
<my:Decline>0</my:Decline>
<my:dcr>0</my:dcr>
<my:Status>Completed</my:Status>
</my:myFields>
But again the task was updated but the workflow didn't move forward.
Update #4
I have made one last trial with SharePoint server object model however, again, the task is updated but the workflow is not moving forward.
Here is my code:SPSite site = new SPSite("http://sitenamehere/");
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["Shared Documents"];
//SPListItem item = list.GetItemById(18);
SPListItem item = list.GetItemByUniqueId(new Guid("5300d16e-94f8-4338-8206-4a57ab7c369b"));
SPWorkflow workflow = item.Workflows[0];
SPWorkflowTask task = workflow.Tasks[0];
Hashtable ht = new Hashtable();
ht[SPBuiltInFieldId.Completed] = "TRUE";
ht["Completed"] = "TRUE";
ht[SPBuiltInFieldId.PercentComplete] = 1.0f;
ht["PercentComplete"] = 1.0f;
ht["Status"] = "Completed";
ht[SPBuiltInFieldId.TaskStatus] = SPResource.GetString(new CultureInfo((int)task.Web.Language, false), Strings.WorkflowStatusCompleted, new object[0]);
//ht["TaskStatus"] = "#";
//ht["ows_TaskStatus"] = "Approved";
//ht["FormData"] = SPWorkflowStatus.Completed;
//ht["Outcome"] = "Approved";
//task.ModerationInformation.Status = SPModerationStatusType.Approved;
web.AllowUnsafeUpdates = true;
SPWorkflowTask.AlterTask((task as SPListItem), ht, true);
}
After a lot of trials and investigation I just had the following code working to approve the task
SPSite site = new SPSite("http://servername/");
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["TestList"];
SPListItem item = list.GetItemById(22);
SPWorkflow workflow = item.Workflows[0];
SPWorkflowTask task = workflow.Tasks[0];
Hashtable ht = new Hashtable();
ht[SPBuiltInFieldId.Completed] = "TRUE";
ht["Completed"] = "TRUE";
ht[SPBuiltInFieldId.PercentComplete] = 1.0f;
ht["PercentComplete"] = 1.0f;
ht["Status"] = "Completed";
ht[SPBuiltInFieldId.TaskStatus] = SPResource.GetString(new CultureInfo((int)task.Web.Language, false), Strings.WorkflowStatusCompleted, new object[0]);
ht[SPBuiltInFieldId.WorkflowOutcome] = "Approved";
ht["TaskStatus"] = "Approved";
ht["FormData"] = SPWorkflowStatus.Completed;
web.AllowUnsafeUpdates = true;
SPWorkflowTask.AlterTask((task as SPListItem), ht, true);
}
I suspect that ht["TaskStatus"] = "Approved"; is that attribute that solved it. Anyway I will try to narrow on the set of properties that need to be changed.
You can use the following code that uses the lists web service and the UpdateListItems method. The key is to use the Cmd='Moderate'
public static XmlNode UpdateListItemApprove()
{
listservice.Lists listProxy = new listservice.Lists();
string xml = "<Batch OnError='Continue'><Method ID='1' Cmd='Moderate'><Field Name='ID'/><Field Name='FileRef'>http://basesmcdev2/sites/tester1/approvals/KL022030.lic</Field><Field Name=\"_ModerationStatus\" >0</Field></Method></Batch>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlNode batchNode = doc.SelectSingleNode("//Batch");
listProxy.Url = "http://basesmcdev2/sites/tester1/_vti_bin/lists.asmx";
listProxy.UseDefaultCredentials = true;
XmlNode resultNode = listProxy.UpdateListItems("approvals", batchNode);
return resultNode;
}
I'm not sure if Madhur's solution works on the associated item or on the task, but to update the task try:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<UpdateListItems
xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<listName>Tasks</listName>
<updates>
<Batch OnError="Continue" ListVersion="1">
<Method ID="1" Cmd="Update">
<Field Name="ID">199</Field>
<Field Name="Outcome">Approved</Field>
<Field Name="Status">Completed</Field>
<Field Name="ows_TaskStatus">Approved</Field>
</Method>
</Batch>
</updates>
</UpdateListItems>
</soap:Body>
</soap:Envelope>
Info on the service:
http://objectmix.com/sharepoint/800144-updatelistitems-web-service-does-not-update-field.html
Info on the approved field:
http://social.msdn.microsoft.com/Forums/en/sharepointworkflow/thread/6712d379-2df6-4223-9a29-b2e60493f1b6
http://social.msdn.microsoft.com/Forums/en/sharepointworkflow/thread/3dc95190-cc61-4067-ac35-2d1a82fad499

How do I view the SQL that is generated by nHibernate?

How do I view the SQL that is generated by nHibernate? version 1.2
You can put something like this in your app.config/web.config file :
in the configSections node :
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
in the configuration node :
<log4net>
<appender name="NHibernateFileLog" type="log4net.Appender.FileAppender">
<file value="logs/nhibernate.txt" />
<appendToFile value="false" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{HH:mm:ss.fff} [%t] %-5p %c - %m%n" />
</layout>
</appender>
<logger name="NHibernate.SQL" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="NHibernateFileLog"/>
</logger>
</log4net>
And don't forget to call
log4net.Config.XmlConfigurator.Configure();
at the startup of your application, or to put
[assembly: log4net.Config.XmlConfigurator(Watch=true)]
in the assemblyinfo.cs
In the configuration settings, set the "show_sql" property to true.
I am a bit late I know, but this does the trick and it is tool/db/framework independent.
Instead of those valid options, I use NH Interceptors.
At first, implement a class which extends NHibernate.EmptyInterceptor and implements NHibernate.IInterceptor:
using NHibernate;
namespace WebApplication2.Infrastructure
{
public class SQLDebugOutput : EmptyInterceptor, IInterceptor
{
public override NHibernate.SqlCommand.SqlString
OnPrepareStatement(NHibernate.SqlCommand.SqlString sql)
{
System.Diagnostics.Debug.WriteLine("NH: " + sql);
return base.OnPrepareStatement(sql);
}
}
}
Then, just pass an instance when you open your session. Be sure to do it only when in DEBUG:
public static void OpenSession() {
#if DEBUG
HttpContext.Current.Items[SessionKey] = _sessionFactory.OpenSession(new SQLDebugOutput());
#else
HttpContext.Current.Items[SessionKey] = _sessionFactory.OpenSession();
#endif
}
And that's it.
From now on, your sql commands like these...
var totalPostsCount = Database.Session.Query<Post>().Count();
var currentPostPage = Database.Session.Query<Post>()
.OrderByDescending(c => c.CreatedAt)
.Skip((page - 1) * PostsPerPage)
.Take(PostsPerPage)
.ToList();
.. are shown straight in your Output window:
NH: select cast(count(*) as INT) as col_0_0_ from posts post0_
NH:select post0_.Id as Id3_, post0_.user_id as user2_3_, post0_.Title as
Title3_, post0_.Slug as Slug3_, post0_.Content as Content3_,
post0_.created_at as created6_3_, post0_.updated_at as updated7_3_,
post0_.deleted_at as deleted8_3_ from posts post0_ order by
post0_.created_at desc limit ? offset ?
In the configuration settings, set the "show_sql" property to true.
This will cause the SQL to be output in NHibernate's logfiles courtesy of log4net.
Use sql server profiler.
EDIT (1 year later): As #Toran Billups states below, the NHibernate profiler Ayende wrote is very very cool.
You can also try NHibernate Profiler (30 day trial if nothing else). This tool is the best around IMHO.
This will not only show the SQL generated but also warnings/suggestions/etc
There is a good reference for NHibernate logging at: How to configure Log4Net for use with NHibernate. It includes info on logging all NHibernate-generated SQL statements.
Nhibernate Profiler is an option, if you have to do anything serious.
If you're using SQL Server (not Express), you can try SQL Server Profiler.
Or, if you want to show the SQL of a specific query, use the following method (slightly altered version of what suggested here by Ricardo Peres) :
private String NHibernateSql(IQueryable queryable)
{
var prov = queryable.Provider as DefaultQueryProvider;
var session = prov.Session as ISession;
var sessionImpl = session.GetSessionImplementation();
var factory = sessionImpl.Factory;
var nhLinqExpression = new NhLinqExpression(queryable.Expression, factory);
var translatorFactory = new NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory();
var translator = translatorFactory.CreateQueryTranslators(nhLinqExpression, null, false, sessionImpl.EnabledFilters, factory).First();
var sql = translator.SQLString;
var parameters = nhLinqExpression.ParameterValuesByName;
if ( (parameters?.Count ?? 0) > 0)
{
sql += "\r\n\r\n-- Parameters:\r\n";
foreach (var par in parameters)
{
sql += "-- " + par.Key.ToString() + " - " + par.Value.ToString() + "\r\n";
}
}
return sql;
}
and pass to it a NHibernate query, i.e.
var query = from a in session.Query<MyRecord>()
where a.Id == "123456"
orderby a.Name
select a;
var sql = NHibernateSql(query);
You are asking only for viewing; but this answer explains how to log it to file. Once logged, you can view it in any text editor.
Latest versions of NHibernate support enabling logging through code. Following is the sample code that demonstrates this. Please read the comments for better understanding.
Configuration configuration = new Configuration();
configuration.SetProperty(NHibernate.Cfg.Environment.Dialect, ......);
//Set other configuration.SetProperty as per need
configuration.SetProperty(NHibernate.Cfg.Environment.ShowSql, "true"); //Enable ShowSql
configuration.SetProperty(NHibernate.Cfg.Environment.FormatSql, "true"); //Enable FormatSql to make the log readable; optional.
configuration.AddMapping(......);
configuration.BuildMappings();
ISessionFactory sessionFactory = configuration.BuildSessionFactory();
//ISessionFactory is setup so far. Now, configure logging.
Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository(Assembly.GetEntryAssembly());
hierarchy.Root.RemoveAllAppenders();
FileAppender fileAppender = new FileAppender();
fileAppender.Name = "NHFileAppender";
fileAppender.File = logFilePath;
fileAppender.AppendToFile = true;
fileAppender.LockingModel = new FileAppender.MinimalLock();
fileAppender.Layout = new PatternLayout("%d{yyyy-MM-dd HH:mm:ss}:%m%n%n");
fileAppender.ActivateOptions();
Logger logger = hierarchy.GetLogger("NHibernate.SQL") as Logger;
logger.Additivity = false;
logger.Level = Level.Debug;
logger.AddAppender(fileAppender);
hierarchy.Configured = true;
You can further play with FileAppender and Logger as per your need. Please refer to this answer and this resource for more details. This explains the same with XML configuration; but the same should equally apply to code.