Do I need to dispose SPWeb here...? - sharepoint

protected void getNews()
{
using (SPWeb web = getWeb("InternalNews"))
{
fetchNewsFromWeb(ref dtNews,true,"English",new string[] { "Internal news page" },web,startDate,endDate,false,true);
}
}
protected SPWeb getWeb(string contentTypeUrlKey)
{
try
{
List<string> urls = CTUrlWrapper.GetContentTypeUrl(contentTypeUrlKey, this.Page.Request.Url.ToString());
return SPContext.Current.Site.OpenWeb(urls[0].ToLowerInvariant().Replace(SPContext.Current.Site.Url.ToLowerInvariant(), "").TrimStart('/'));
}
catch
{
throw new Exception("Can not fetch value from CTUrl list, key: \"" + contentTypeUrlKey + "\"");
}
}
Do I really need to dispose the web in fetchNewsFromWeb method?
protected DataTable fetchNewsFromWeb(ref DataTable dtAllData, bool useCriticalField, string pageLanguage, string[] contentTypes, SPWeb web, DateTime? fromDate, DateTime? toDate, bool otherUnitNews, bool useHeaderPrefix)
{
SPSiteDataQuery sdq = GetQuery(useCriticalField);
StringBuilder sbQuery = new StringBuilder();
sbQuery.Append(getWhereClause(pageLanguage, fromDate, toDate, contentTypes, otherUnitNews));
sbQuery.Append(getOrderByClause(useCriticalField));
sdq.Query = sbQuery.ToString();
try
{
DataTable foundItems = web.GetSiteData(sdq);
if (foundItems.Rows.Count > 0)
{
foreach (DataRow row in foundItems.Rows)
{
try
{
object[] dtAlldataTemp = extractNewsFields(row, useHeaderPrefix);
dtAllData.Rows.Add(dtAlldataTemp);
}
catch (Exception ex)
{
}
}
}
}
catch (Exception ex)
{
}
finally {web.Dispose();}// do we really need this here?
return dtAllData;
}
protected SPWeb getWeb(string contentTypeUrlKey)
{
try
{
List<string> urls = CTUrlWrapper.GetContentTypeUrl(contentTypeUrlKey, this.Page.Request.Url.ToString());
return SPContext.Current.Site.OpenWeb(urls[0].ToLowerInvariant().Replace(SPContext.Current.Site.Url.ToLowerInvariant(), "").TrimStart('/'));
}
catch
{
throw new Exception("Can not fetch value from CTUrl list, key: \"" + contentTypeUrlKey + "\"");
}
}

No you don't.
The using will take care of disposing it already.

Did you ask SPDisposeCheck?

It depends on how getWeb function is returning the SPWeb.
If its just a SPContext.Current.Web - > Answer is No.
If its returned by opening a new web using OpenWeb() call. Answer is Yes.

Can you not pass the web by ref and have the outer dispose take are of it?

Related

How do I create a Windows Service using Threading and multiple HttpWebRequest async calls?

I need help with creating a windows service using Threading and asynchronous HttpWebRequest calls. I have created a few C# windows services before but never using threading. Also, I seem to be getting hung up with the async calls using HttpWebRequest. I have googled this as well as looking on this site. I could not find anything that helped. This is mainly because I could not seem to get what was presented in other questions to work in my specific example.
Please keep in mind that I may be overlapping things based on my lack of knowledge in this specific area as well as through trying to figure it out.
The main flow of this is to get a list of urls during onStart. Typically this list would be retrieved from a _facade.GetUrls call. Then, at each time interval call scanSites. A request is made to each url and then I save the results to the database in _facade.SaveUrlResponse.
My problems is it seems as if I am caught in an endless loop when I debug it. I am not exactly sure how/where to do this. Thanks in advance.
Here is what I have:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.ServiceProcess;
using System.Threading;
using URLValidation.BusinessManager.Facade;
using URLValidation.BusinessManager.Model;
namespace URLValidation
{
partial class URLValidation : ServiceBase
{
#region " class variables "
private System.Timers.Timer _timer;
private List<UrlModel> _url_List = null;
private Facade _facade;
private Thread _t;
private int _x;
#endregion
public URLValidation()
{
_facade = new Facade();
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
_url_List = new List<UrlModel>
{
new UrlModel(address: "http://www.google.com", addressID: 1),
new UrlModel(address: "http://www.microsoft.com", addressID: 2),
new UrlModel(address: "http://www.stackoverflow.com", addressID: 3)
};
resetTimer();
GC.KeepAlive(_timer);
}
catch (Exception ex)
{
throw ex;
}
}
private void resetTimer()
{
try
{
_timer = new System.Timers.Timer();
_timer.Interval = 10000;//1800000; //30 minutes
_timer.Start();
_timer.Enabled = true;
_timer.Elapsed += scanSites;
}
catch (Exception ex)
{
throw ex;
}
}
private void scanSites(object sender, System.Timers.ElapsedEventArgs e)
{
_timer.Stop();
_x = 0;
_t = new Thread(new ThreadStart(scanSites));
_t.IsBackground = true;
_t.Start();
}
private void scanSites()
{
try
{
foreach (UrlModel url in _url_List)
{
_x += 1;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url.Address);
request.Method = "HEAD";
RequestModel requestModel = new RequestModel(request, url);
IAsyncResult result = request.BeginGetResponse(new AsyncCallback(saveUrlResponse), requestModel);
ThreadPool.RegisterWaitForSingleObject
(
result.AsyncWaitHandle,
new WaitOrTimerCallback(ScanTimeoutCallback),
requestModel,
(30 * 1000), // 30 second timeout
true
);
}
}
catch (Exception ex)
{
throw ex;
}
}
private void saveUrlResponse(IAsyncResult result)
{
//grab the custom state object
RequestModel requestModel = (RequestModel)result.AsyncState;
HttpWebRequest request = (HttpWebRequest)requestModel.Request;
//get the Response
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
// process the response...
ResponseModel responseModel = new ResponseModel(request, response, requestModel.UrlModel.AddressID);
_facade.SaveUrlResponse(responseModel);
}
private void ScanTimeoutCallback(object requestModel, bool timedOut)
{
if (timedOut)
{
RequestModel reqState = (RequestModel)requestModel;
if (reqState != null)
reqState.Request.Abort();
}
if (_x == _url_List.Count)
{
resetTimer();
}
}
protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
}
}
}
Okay, I think I am getting somewhere. I have moved my code to a console app. I am able to get the results saved to the database by using either GetResponse (sync) and BeginGetResponse (async). From what I can tell I believe this is a good solution. Can somebody verify this and let me know if you foresee any problems once this is moved to a Windows Service. Here is the new code
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
namespace ConsoleApplication2
{
static class Program
{
private static List<UrlModel> _url_List = null;
private static Object _acctLock = new object();
private static Facade _facade = new Facade();
static void Main(string[] args)
{
_url_List = new List<UrlModel>
{
new UrlModel(address: "http://www.microsoft.com", addressID: 1),
new UrlModel(address: "http://www.google.com", addressID: 2),
new UrlModel(address: "http://www.stackoverflow.com", addressID: 3)
};
lockThreadAndGetUrlStatus(_url_List);
Console.ReadLine();
}
static void lockThreadAndGetUrlStatus(List<UrlModel> _url_List)
{
Thread[] threads;
try
{
threads = new Thread[_url_List.Count];
Thread.CurrentThread.Name = "main";
int i = 0;
foreach (UrlModel url in _url_List)
{
//Thread t = new Thread(() => scanSites(url));
Thread t = new Thread(() => scanSitesWithAsync(url));
t.Name = i.ToString();
threads[i] = t;
i += 1;
}
for (i = 0; i < _url_List.Count; i++)
{
Console.WriteLine("Thread {0} Alive : {1}", threads[i].Name, threads[i].IsAlive);
threads[i].Start();
Console.WriteLine("Thread {0} Alive : {1}", threads[i].Name, threads[i].IsAlive);
}
Console.WriteLine("Current Priority : {0}", Thread.CurrentThread.Priority);
Console.WriteLine("Thread {0} Ending", Thread.CurrentThread.Name);
}
catch (Exception ex)
{
throw ex;
}
}
static void scanSitesWithAsync(UrlModel url)
{
try
{
lock (_acctLock)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url.Address);
request.Method = "HEAD";
RequestModel requestModel = new RequestModel(request, url);
IAsyncResult result = request.BeginGetResponse(new AsyncCallback(saveUrlResponseWithAsync), requestModel);
ThreadPool.RegisterWaitForSingleObject
(
result.AsyncWaitHandle,
new WaitOrTimerCallback(scanTimeoutCallback),
requestModel, 30000, true
);
}
}
catch (Exception ex)
{
throw ex;
}
}
static void saveUrlResponseWithAsync(IAsyncResult result)
{
try
{
RequestModel requestModel = (RequestModel)result.AsyncState;
HttpWebRequest request = (HttpWebRequest)requestModel.Request;
//get the Response
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
// process the response...
ResponseModel responseModel = new ResponseModel(requestModel.Request, response, requestModel.UrlModel.AddressID);
_facade.SaveUrlResponse(responseModel);
Console.WriteLine(response.StatusCode);
}
catch (Exception ex)
{
throw ex;
}
}
static void scanTimeoutCallback(object requestModel, bool timedOut)
{
try
{
if (timedOut)
{
RequestModel reqState = (RequestModel)requestModel;
if (reqState != null)
reqState.Request.Abort();
}
}
catch (Exception ex)
{
throw ex;
}
}
}
}
looks like you are trying to issue 3 async requests at the same time. By default, the HTTP/1.1 protocol only specifies 2 connections

JSF exporting excel data from another page

I am new to jsf and I am setting up a basic reporting tool (sql queries) which shows a list of reports in the home page. I want to put an excel export commandbutton in the home page and export the report selected by the user or drive the user to a different execution page to show results in a datatable for the selected report. How can I achieve that? datatable with query results, of course, is visible only in the execution page and is dynamically created during query execution (this part works fine). Am I going crazy for nothing? Thanks in advance for any suggestion.
If you want to export data to Excel you need to use a third party library. There are free ones like JExcelApi and Apache POI. Also, there are commercial libraries like Aspose. If you're going to choose an open source library check this question: Choosing an excel java api.
When you export data to Excel, you must create the Excel file and download the content for the client. You can check how to download a file using JSF by #BalusC (JSF expert).
One more advice, when you're downloading a file don't add ajax functionality to the command link/button.
You can use under code this code block provide excel export as genericly way. You can send any List and send any fileName
public class ExcelUtils {
public static <T> void writeToExcel(String fileName, List<T> data) {
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xls");
response.setHeader("Pragma", "no-cache");
OutputStream fos = null;
try {
fos = response.getOutputStream();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
XSSFWorkbook workbook = null;
try {
// File file = new File(fileName);
workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet();
List<String> fieldNames = getFieldNamesForClass(data.get(0).getClass());
int rowCount = 0;
int columnCount = 0;
Row row = sheet.createRow(rowCount++);
for (String fieldName : fieldNames) {
if (!fieldName.equals("serialVersionUID")) {
Cell cell = row.createCell(columnCount++);
cell.setCellValue(fieldName);
}
}
Class<? extends Object> classz = data.get(0).getClass();
for (T t : data) {
row = sheet.createRow(rowCount++);
columnCount = 0;
for (String fieldName : fieldNames) {
if (!fieldName.equals("serialVersionUID")) {
Cell cell = row.createCell(columnCount);
Method method = null;
try {
method = classz.getMethod("get" + capitalize(fieldName));
} catch (NoSuchMethodException nme) {
method = classz.getMethod("get" + fieldName);
}
Object value = method.invoke(t, (Object[]) null);
if (value != null) {
if (value instanceof String) {
cell.setCellValue((String) value);
} else if (value instanceof Long) {
cell.setCellValue((Long) value);
} else if (value instanceof Integer) {
cell.setCellValue((Integer) value);
} else if (value instanceof Double) {
cell.setCellValue((Double) value);
}
}
columnCount++;
}
}
}
workbook.write(fos);
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.close();
context.responseComplete();
context.renderResponse();
}
} catch (IOException e) {
}
try {
if (workbook != null) {
workbook.close();
}
} catch (IOException e) {
}
}
}
// retrieve field names from a POJO class
private static List<String> getFieldNamesForClass(Class<?> clazz) throws Exception {
List<String> fieldNames = new ArrayList<String>();
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fieldNames.add(fields[i].getName());
}
return fieldNames;
}
// capitalize the first letter of the field name for retriving value of the
// field later
private static String capitalize(String s) {
if (s.length() == 0)
return s;
return s.substring(0, 1).toUpperCase() + s.substring(1);
}
}

How to get the context from workflow event handler in Sharepoint 2010

I am in the process of upgrading our custom solutions to Sharepoint 2010. I wanted to utilize the WorkflowCompleted event handler but I don't seem to be able to get the relevant SPListItem from the event properties.
I tried using SPWorkflowEventProperties.ActivationProperties but this always returns null (even in the WorkflowStarted event handler).
How do I get the context from workflow event handlers (SPListItem, SPWeb, SPSite etc)?
I've found the same thing. SPWorkflowEventProperties is practically useless since just about everything is null. It doesn't tell status (Approved, Rejected, etc). And, most importantly, it doesn't (directly) tell what item was completed. Hopefully this will be addressed in future versions. In the meantime, I used the following:
public override void WorkflowCompleted(SPWorkflowEventProperties properties)
{
using (SPSite site = new SPSite(properties.WebUrl))
{
using (SPWeb web = site.OpenWeb())
{
SPListItem task = GetApprovedTask(properties, web);
SPListItem item = GetApprovedItem(web, task);
if (null != item)
{
// TODO : process approved item
}
}
}
}
private SPListItem GetApprovedItem(SPWeb web, SPListItem task)
{
SPListItem item = null;
if (null != task)
{
SPList list = web.Lists[new Guid(task[SPBuiltInFieldId.WorkflowListId].ToString())];
item = list.GetItemById((int)task[SPBuiltInFieldId.WorkflowItemId]);
}
return item;
}
private SPListItem GetApprovedTask(SPWorkflowEventProperties properties, SPWeb web)
{
SPListItem item = null;
string caml = #"<Where><And><And><And><Eq><FieldRef Name='WorkflowOutcome' /><Value Type='Text'>Approved</Value></Eq><Eq><FieldRef Name='WorkflowInstanceID' /><Value Type='Guid'>{0}</Value></Eq></And><IsNotNull><FieldRef Name='WorkflowListId' /></IsNotNull></And><IsNotNull><FieldRef Name='WorkflowItemId' /></IsNotNull></And></Where>";
SPQuery query = new SPQuery();
query.Query = string.Format(caml, properties.InstanceId);
query.RowLimit = 1;
SPList list = web.Lists["Tasks"];
SPListItemCollection items = list.GetItems(query);
if (items.Count > 0)
{
item = items[0];
}
return item;
}
You can use the InstanceId property to retrieve the SPListItem from the workflow task list as shown in this post
http://blog.symprogress.com/2011/09/sp-2010-get-workflow-status-workflowcompleted-event/
If you can be more generous with details I can be more specific with answer.
But this is generally what you need to do:
Set context specific properties
public static DependencyProperty _ContextProperty
= System.Workflow.ComponentModel.DependencyProperty.Register("_Context",
typeof(WorkflowContext), typeof(MyCustomActivity));
[Description("Site Context")]
[Category("User")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public WorkflowContext __Context
{
get
{
return ((WorkflowContext)(base.GetValue(MyCustomActivity.__ContextProperty)));
}
set
{
base.SetValue(MyCustomActivity.__ContextProperty, value);
}
}
public static DependencyProperty __ListIdProperty
= System.Workflow.ComponentModel.DependencyProperty.Register("__ListId",
typeof(string), typeof(MyCustomActivity));
[ValidationOption(ValidationOption.Required)]
public string __ListId
{
get
{
return ((string)(base.GetValue(MyCustomActivity.__ListIdProperty)));
}
set
{
base.SetValue(MyCustomActivity.__ListIdProperty, value);
}
}
public static DependencyProperty __ListItemProperty
= System.Workflow.ComponentModel.DependencyProperty.Register("__ListItem",
typeof(int), typeof(MyCustomActivity));
[ValidationOption(ValidationOption.Required)]
public int __ListItem
{
get
{
return ((int)(base.GetValue(MyCustomActivity.__ListItemProperty)));
}
set
{
base.SetValue(MyCustomActivity.__ListItemProperty, value);
}
}
public static DependencyProperty __ActivationPropertiesProperty
= DependencyProperty.Register("__ActivationProperties",
typeof(Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties), typeof(MyCustomActivity));
[ValidationOption(ValidationOption.Required)]
public Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties __ActivationProperties
{
get
{
return (Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties)base.GetValue(MyCustomActivity.__ActivationPropertiesProperty);
}
set
{
base.SetValue(MyCustomActivity.__ActivationPropertiesProperty, value);
}
}
You will get context in __Context and everything else from __Context like this:
protected override ActivityExecutionStatus
Execute(ActivityExecutionContext executionContext) {
// Raise Invoke Event to execute custom code in the workflow.
this.RaiseEvent(MyCustomActivity.InvokeEvent,
this, EventArgs.Empty);
SPWeb _cxtWeb = null;
String _strLinfo = "Dll;";
String _strTo = String.Empty;
// Set Context
try
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (_cxtWeb = __Context.Web)
{
//_cxtWeb = __Context.Web;
Guid _cListId = new Guid(__ListId);
SPList _cSPList = _cxtWeb.Lists[_cListId]; // TimeLog
SPListItem _cListItem = _cSPList.GetItemById(__ListItem);
SMTPSERVER = _cxtWeb.Site.WebApplication
.OutboundMailServiceInstance.Server.Address;
}
});
}
catch { /**/ }
}

Passing a string from web part to user control

public class ToolPartGetLists : Microsoft.SharePoint.WebPartPages.WebPart, ICommunicationInterface
{
private bool _error = false;
//.........
protected override void CreateChildControls()
{
if (!_error)
{
try
{
ViewState["prodList"] = SelectedList;
//base.CreateChildControls();
Office_Cp = (OfficeCPS)Page.LoadControl(#"/_controltemplates/OfficeCP/OfficeCP.ascx");
this.Controls.Add(Office_Cp);
// Your code here...
//this.Controls.Add(new LiteralControl(this.MyProperty));
}
catch (Exception ex)
{
HandleException(ex);
}
}
}
}
public class OfficeCPS : System.Web.UI.UserControl
{
//I want the value of Selected List here
public string prodDataList = "";
//.......
}
I tried ViewState, not working!!!
Inside the try you could use:
Office_Cp = (OfficeCPS)Page.LoadControl(#"/_controltemplates/OfficeCP/OfficeCP.ascx");
this.Controls.Add(Office_Cp);
Office_Cp.prodDataList = SelectedList;
If this doesn't work pay careful attention to how you are handling the ASP.NET lifecycle.
Also note it would be better practice to hide prodDataList behind a property or method.

How to get the URL for a SharePoint Discussion Board entry?

How do you retrieve the URL for a discussion board item? That is, the URL displayed when you mouse over the subject line (once the list has been added to the page as a web part).
protected global::System.Web.UI.WebControls.GridView gvForum;
public string Region
{
get
{
return "";
}
}
public string DefaultRegion { get; set; }
public int Top { get; set; }
public string ListName
{
get
{
string listName=string.Empty;
if (!string.IsNullOrEmpty(this.Region))
listName=string.Format("{0} {1}","Forum",this.Region);
else
listName = string.Format("{0} {1}", "Forum", this.DefaultRegion);
return listName;
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGrid();
}
}
private void BindGrid()
{
string region = this.Region;
string caml=#"<OrderBy><FieldRef Name=""Modified"" /></OrderBy>";
try
{
using (SPSite spSite = new SPSite(SPContext.Current.Site.Url))
{
using (SPWeb spWeb = spSite.OpenWeb())
{
SPQuery spQ = new SPQuery();
spQ.Query = caml;
spQ.RowLimit = (uint)this.Top;
SPList spList = spWeb.Lists[ListName];
SPListItemCollection items = spList.GetItems(spQ);
if (items != null && items.Count > 0)
{
gvForum.DataSource = items;
gvForum.DataBind();
}
else
{
this.Visible = false;
}
}
}
}
catch (Exception ex)
{
Logger.Log(ex.Message, System.Diagnostics.EventLogEntryType.Error);
}
}
protected void gvForum_RowDataBound(object sender, GridViewRowEventArgs e)
{
SPListItem item = e.Row.DataItem as SPListItem;
Label lblTitle = e.Row.FindControl("lblTitle") as Label;
HtmlAnchor aURL = e.Row.FindControl("aURL") as HtmlAnchor;
if (item != null)
{
if (lblTitle != null && aURL != null)
{
aURL.HRef = "~/" + item.Url;
lblTitle.Text = item["Title"].ToString();
}
}
}
protected void gvForum_RowDataBound(object sender, GridViewRowEventArgs e)
{
SPListItem item = e.Row.DataItem as SPListItem;
Label lblTitle = e.Row.FindControl("lblTitle") as Label;
HtmlAnchor aURL = e.Row.FindControl("aURL") as HtmlAnchor;
if (item != null)
{
if (lblTitle != null && aURL != null)
{
aURL.HRef = "~/" + item.Url;
lblTitle.Text = item["Title"].ToString();
}
}
}
You can use use "TopicPageUrl" field column to directly get the discussion topic by using REST api URL
http://sp2013.in/_api/web/Lists/GetByTitle('Discussion')/Items?$select=Title,TopicPageUrl,DiscussionLastUpdated,Folder/ItemCount,LastReplyBy/Title,Author/Title&$expand=Folder,LastReplyBy,Author&$orderby=DiscussionLastUpdated desc
The above code is also useful to get discussion last updated, reply count (its saved in folder), last replied by.
Are you asking how to find the URL for an individual discussion in a discussion board? Or an individual reply to a discussion?
You can give just subject name like http://site/discussion/lists/discussionboard/discusontitlename or subject
You may not have the list item, but if you do just look at the "FileRef" property. It will look like "https://mycompany.sharepoint.com/sites/Lists/discussion/". If I put that URL in the browser (I'm using SharePoint Online), it redirects me to the https://mycompany.sharepoint.com/Lists/Discussion/Flat.aspx?RootFolder=... URL.
To generate the direct url to a particular discussion item, on Client side (using a REST API call), you could try this:
var jqXhr = $.ajax({
url:"/DiscussionSite/_api/lists/getByTitle('Discussions')/items?
$select=ID,FileRef,ContentTypeId,Title,Body&
$filter=ContentType eq 'Discussion'",
headers: { 'Accept': 'application/json;odata=verbose'}
});
// Fetch only the discussions from the Discussion list (excl. Messages)
jqXhr.done(function(data){
// Picking only the first item for testing purpose
// Feel free to loop through the response if necessary
var firstItem = data.d.results[0],
firstItemUrl = '/DiscussionSite/Lists/Discussions/Flat.aspx?RootFolder=' + firstItem.FileRef + '&FolderCTID' + firstItem.ContentTypeId;
// Result - /DiscussionSite/Lists/Discussions/Flat.aspx?RootFolder=/DiscussionSite/Lists/Discussions/My Discussion Topic 1&FolderCTID0x01200200583C2BEAE375884G859D2C5A3D2A8C06
// You can append "&IsDlg=1" to the Url for a popup friendly display of the Discussion Thread in a SharePoint Modal Dialog
console.log(firstItemUrl);
});
Hope this helps!

Resources