개발이 끝나는 무렵… 이제 성능 테스트와… 벌래(bug)를 찾아 삼만리 하게 됩니다.

쉐어포인트에는 참 좋은 성능 확인과 벌래 잡이용 대시보드라는게 있습니다.

 

일단 실행은 아래와 같이 입력하시면 됩니다.

Sharepoint 2010 Management Shell을 실행하고..

 

아래와 같이 입력하시면 됩니다.

시작
stsadm -o setproperty -pn developer-dashboard -pv on

종료
stsadm -o setproperty -pn developer-dashboard -pv off

 

위의 내용은 아래 링크에서 좀 더 자세히 볼 수 있습니다.

http://msdn.microsoft.com/en-us/library/ff512745.aspx

 

그리고 실행하게 되면 아래와 같은 화면을 볼 수 있습니다.

 

여기에서 좌측의 노란 색 영역은 현재 페이지에 실행되는 액션 대비 시간이라고 생각하시면 되고..

우측의 상단 빨간색 영역은 오류내용을 표시합니다.

선택 시 좀 더 자세한 내용을 확인 할 수 있고요..

빨간 색의 내용 중 90hv에 관한 내용은 이전에 적어 놓은 포스트에서 확인 하시기 바랍니다.

2013/03/07 - [SharePoint 2010/Development] - Sharepoint 2010 - Detected use of SPRequest for previously closed SPWeb object



그리고 마지막 우측하단 파란색 영역은 실행된 모든 프로시저에 관한 내용을 확인 할 수 있습니다.

여기 프로시저에서 중요한 내용이 있는데..

DECLARE @DocParentIdForRF 라고 되어 있는 프로시저의 경우에는 한번씩 확인을 해 줘야 합니다.

 

해당 프로시저를 선택하면 위와 같이 자세한 내용을 볼 수 있습니다.

제가 하이라이트 표시 해 놓은 부분에 만약 SELECT TOP (@NUMROWS) 라고 되어 있다면 @NUMROWS의 VALUE도 확인하셔야 합니다.

아래와 같이 2,147,483,648 으로 설정될 수 있습니다.

 

성능상의 문제가 될 수 있는 요인이 있기 때문에 반드시 확인하셔야 합니다.

해당 코드는 대략 아래와 같이 구분 할 수 있습니다.

  • SP Item의 인덱스 접근 말고 GetItemById 등과 같은 코드로 접근 할 것
    • item = targetList.Items[int]; X
    • item = targetList.GetItemById(int); O
  • SPQuery 사용 시 반드시 RowLimit를 지정 할 것!
    • Query.RowLimit = 10;
  • 게시판의 카운트를 구할 때 List.ItemCount 와 같이 접근 할 것
    • int total = SPContext.Current.List.Items.Count; X
    • int total = SPContext.Current.List.ItemCount; O

 

위와 같이 해 주시면 저런 21억 Row 쿼리가 실행 되지 않습니다.

 

그리고 위의 화면에 짤린 부분이 있습니다.

 

이 부분인데 Service Calls 부분에서 WebPart Events Offsets 부분만 확인하시면 됩니다.

여기에는 각 웹파트 별로  OnLoad 시점의 시간이 나타나게 되는데요…

급격히 증가하는 웹파트를 찾아서.. 튜닝해 주는 방법을 이용하시면 됩니다.

 

이렇게만 확인해 주셔도.. 페이지의 로딩시간 단축을 확인 할 수 있습니다.

이상입니다.

 

고맙습니다.


개발자 대시보드를 켜 놓고 확인을 하다가 아래와 같은 메시지를 보게 되었습니다.

 

General Unexpected 90hv Detected use of SPRequest for previously closed SPWeb object.  Please close SPWeb objects when you are done with all objects obtained from them, but not before.

 

 

 

위의 메시지는 그 동안 개발하면서 많이 보아 오던 것입니다.

이 녀석이 왜 나타난건지 찾아보게 되었습니다.

저는 SPWeb 객체를 재대로 닫지 않았을 거라고 생각했는데 그게 아니더군요…

 

제가 주로 SPWeb 객체를 사용하는 방법은 일단 아래와 같습니다.

using (SPSite oSite = new SPSite(strListUrl, oUserToken))
using (SPWeb oWeb = oSite.RootWeb)
{
}

 

위의 에러는 아래와 같은 상황에서 발생됩니다.

SPFile oFile = null;
using (SPSite oSite = new SPSite(strListUrl, oUserToken))
using (SPWeb oWeb = oSite.RootWeb)
{
	oFile = oWeb.GetFile("~fileUrl");
}

 

SP 객체를 Web Scope 안에서 해제되도록 코딩 되어야 하는 것입니다.

위의 코드를 아래와 같이 변경하여 처리 해야 하는 거이지요..

string strTitle = String.Empty;
using (SPSite oSite = new SPSite(strListUrl, oUserToken))
using (SPWeb oWeb = oSite.RootWeb)
{
	SPFile oFile = oWeb.GetFile("~fileUrl");
	strTitle = oFile.Title;
}
if(String.IsNullOrEmpty(strTitle))
{
	// 처리
}

 

이렇게 하면 해당 에러가 사라지는 것을 확인 할 수 있습니다.

 

고맙습니다.


 

마이 사이트 쪽을 개발하다가 기존의 Colleagues 웹파트를 추가하고 사용자를 추가하고 난 후 사용자가 하나의 Row로 보이는 것이 아니라 웹파트의 크기 만큼 셀로 보이는 문제가 발생하였습니다.

 

일단 웹파트를 입력한 후 페이지에서 보게 되면 아래와 같이 보이게 됩니다.

 

웹파트 속성을 보게 되면 속성에는 몇 Row를 보이게 할 것인가 라는 속성과 이름이 보일지 말지 결정하는 속성 두가지 밖에 없습니다.

 

이게 셀단위로 증가 되는 경우는 폭이 80 이상이 경우 80으로 나눠서 샐을 만들고 데이터를 입력하는 형태로 개발되어 있습니다.

웹파트에서요…

 

개발되어 있는 곳도 portal.js에서 구형되어 있어 스크립트로만 구현하면 됩니다.

저는 아래와 같이 만들었으며 사이즈 계산하는 곳만 잘 해 놓으시면 될 것 같습니다.

 

소스는 아래와 같습니다.

저는 person.aspx에 넣어 놓았으며, portal.js 보다 아래 쪽에서만 구현되면 됩니다.

/// portal.js override
function MySite_RenderPeople(h, a, c, d, j) {
	ULSX84: ;
	if (j) {
		var k = function () {
			ULSX84: ;
			MySite_RenderPeople(h, a, c, d, false)
		};
		AttachEvent("domLoad", function () {
			ULSX84: ;
			setTimeout(k, 50)
		});

		return
	}

	if (c < 1)
		c = 1;

	// var i = document.getElementById(h), f = i.clientWidth, e = d ? 80 : 55, b = Math.floor(f / e);
	var i = document.getElementById(h), f = i.clientWidth, e = d ? 230 : 55, b = Math.floor(f / e);
	if (b > a.length) {
		b = a.length;
		e = Math.floor(f / b)
	}
	var g = Math.min(a.length, c * b);
	_MySite_RenderPeople(i, a, 0, g, b, e, d, true);

	return g == a.length
}

MySite_RenderPeople 메소드에서 위의 소스에 주석되어 있는 부분에 80을 원하는 넓이 값으로만 변경하시면 됩니다.
이상입니다.
 
고맙습니다.


어제 오늘 삽질한 결과 결론은 Web Application Page에서는 안된다!! 라는 참혹한 결과를 얻었습니다.

Prefix의 경우 제가 하고자 하는 방식은 다음과 같습니다.

해당 Url에 Prefix가 있는지 검사해서. 없으면 만드는 아주 단순한 방식의 프로그래밍..

 

소스는 아래와 같습니다.

SPWebApplication webApp = SPWebApplication.Lookup(new Uri(strHostUrl));
SPPrefixCollection prefixColl = webApp.Prefixes;
if (prefixColl.Contains(txtSitePrefix.Text.Trim()) == false)
{
    SPPrefix newPrefix = webApp.Prefixes.Add(txtSitePrefix.Text.Trim(), SPPrefixType.ExplicitInclusion);
}

위의 코드 중 Prefixes.Add 시점에 “액세스가 거부되었습니다.”라는 오류가 발생됩니다.

 

그래서 좀 찾아보니. Microsoft.SharePoint.Administration.SPPersistedObject.BaseUpdate()에서 해당 에러를 반환합니다.

아래 이미지에 if문에서 else 구문으로 빠지는데 거기에 throw new SecurityException(SPResource.GetString("AccessDenied", new object[0]));

되어 있네요.. 흠…

 

이게 참 신기한 것이.. Feature로 만들면 잘 되는데.. 어플리케이션 페이지에서는 안됩니다.

 

그리고 또 하나 WebAppcliation.Features의 remove 또한 안됩니다.

 

그래서. 해결방법이 없다 입니다. ㅠ.ㅠ

누가 잘 하시는 분 이것 좀 해결 해 주세요!!

왜 안되는건지!! ㅠ.ㅠ

쉐어포인트 2010에서 검색페이지의 디자인을 많이 바꾸게 되는데요..

검색결과 웹 파트의 XSL을 변경하여 디자인을 수정하게 될 것입니다.

XSL 편집을 위해서는 Xml Data가 필요한데요.. 검색 시 나오는 결과 페이지에 Xml 확인하는 방법입니다.

확인하는 방법은 http://servername/siteName/Pages/Results.aspx 로 이동 후 Search Core Results 웹파트의 Display를 수정하여 확인하는 방법입니다.

 

MSDN의 페이지를 참조한 것이며 URL은 아래와 같습니다.

http://msdn.microsoft.com/en-us/library/ms546985.aspx

 

방법은 아래와 같습니다.

  1. http://servername/siteName/Pages/Results.aspx 로 이동합니다.
  2. 사이트 작업 –> 페이지 편집
  3. Search core result webpart를 선택한 후 타이틀 영역에 우측 화살표 클릭
  4. 웹 파트 편집 클릭
  5. 속성 표시 –> 위치 시각화 사용 체크 박스 언 체크
  6. XSL 편집기 버튼 클릭
  7. XSL 편집기 창에서 아래의 코드 입력 후 확인

 

Xsl 코드는 아래와 같습니다.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xmp><xsl:copy-of select="*"/></xmp>
</xsl:template>
</xsl:stylesheet>

 

 

 

 

 

 

확인 후 페이지 저장을 선택하시면 아래와 같이 확인 할 수 있습니다.

 

  <All_Results>
    <Result>
      <id>1</id>
      <workid>426</workid>
      <rank>73866856</rank>
      <title>test</title>
      <author></author>
      <size>0</size>
      <url>http://ae-dev/Lists/test/AllItems.aspx</url>
      <urlEncoded>http%3A%2F%2Fae%2Ddev%2FLists%2Ftest%2FAllItems%2Easpx</urlEncoded>
      <description></description>
      <write>9/20/2011</write>
      <sitename>http://ae-dev/Lists/test</sitename>
      <collapsingstatus>0</collapsingstatus>
      <hithighlightedsummary>DiscussionBoard <ddd /> Site Actions <ddd /> This page location is: <ddd /> Roos <ddd /> Subject <ddd /> I Like It <ddd /> Tags &amp; Notes <ddd /> Top Link Bar <ddd /> my page <ddd /> Quick Launch <ddd /> Libraries <ddd /> Site Pages <ddd /> Shared Documents <ddd /> Lists <ddd /> Calendar <ddd /> Tasks <ddd /> Discussions <ddd /> Team <ddd /> All <ddd /> </hithighlightedsummary>
      <hithighlightedproperties>
        <HHTitle>
          <c0>test</c0>
        </HHTitle>
        <HHUrl>http://ae-dev/Lists/<c0>test</c0>/AllItems.aspx</HHUrl>
      </hithighlightedproperties>
      <contentclass>STS_List_DiscussionBoard</contentclass>
      <isdocument>False</isdocument>
      <picturethumbnailurl></picturethumbnailurl>
      <popularsocialtags />
      <picturewidth>0</picturewidth>
      <pictureheight>0</pictureheight>
      <datepicturetaken></datepicturetaken>
      <serverredirectedurl></serverredirectedurl>
      <fileextension>ASPX</fileextension>
      <ows_metadatafacetinfo></ows_metadatafacetinfo>
      <imageurl imageurldescription="토론 게시판">/_layouts/images/itdisc.png</imageurl>
    </Result>
    <Result>
      <id>2</id>
      <workid>263</workid>
      <rank>72043116</rank>
      <title>Roos</title>
      <author></author>
      <size>104863</size>
      <url>http://ae-dev</url>
      <urlEncoded>http%3A%2F%2Fae%2Ddev</urlEncoded>
      <description>Roots</description>
      <write>9/7/2012</write>
      <sitename>http://ae-dev</sitename>
      <collapsingstatus>0</collapsingstatus>
      <hithighlightedsummary>
        <c0>test</c0> <ddd /> Add a new image, change this welcome text or add new lists to this page by clicking the edit button above. You can click on Shared Documents to add files or on the calendar to <ddd /> </hithighlightedsummary>
      <hithighlightedproperties>
        <HHTitle>Roos</HHTitle>
        <HHUrl>http://ae-dev</HHUrl>
      </hithighlightedproperties>
      <contentclass>STS_Site</contentclass>
      <isdocument>False</isdocument>
      <picturethumbnailurl></picturethumbnailurl>
      <popularsocialtags />
      <picturewidth>0</picturewidth>
      <pictureheight>0</pictureheight>
      <datepicturetaken></datepicturetaken>
      <serverredirectedurl></serverredirectedurl>
      <fileextension></fileextension>
      <ows_metadatafacetinfo></ows_metadatafacetinfo>
      <imageurl imageurldescription="SharePoint 사이트 모음">/_layouts/images/siteicon_16x16.png</imageurl>
    </Result>
    <TotalResults>2800</TotalResults>
    <NumberOfResults>50</NumberOfResults>
  </All_Results>

 

화면 출력은 아래와 같습니다.

 

아울러 검색 결과 디자인을 위해서는 아래 XSL을 수정하시면 됩니다.

 

이상입니다.

감사합니다.


Sharepoint 개발 중 가장 중요한 부분인 것 같아.. 꼭 알고 계셔야 할 부분입니다.

역시 가장 잘 설명되어 있는 곳은 MSDN입니다.

http://msdn.microsoft.com/en-us/library/ee557362.aspx

 

SPSite, SPWeb의 코딩에는 반드시 Dispose되어야 합니다.

그 중 Context로 잡은 SPSite, SPWeb의 경우에는 Dispose 할 필요가 없습니다.

 

loop 안에 있는 Site, Web 등의 경우가 좀 중요하다고 할 수 있는데요..

좋은 코딩은 아래와 같습니다.

SPSite oSite = SPContext.Current.Site;
using (SPWeb oWeb = oSite.OpenWeb())
{
	foreach (SPWeb oWeb2 in oWeb.Webs)
	{
		// code...
		oWeb2.Dispose();
	}

	SPWeb oWeb3 = null;
	for (int i = 0; i < oWeb.Webs.Count; i++)
	{
		using (oWeb3 = oWeb.Webs[i])
		{
			// code...
		}
	}
}

using (SPSite site = new SPSite("http://dev.com/"))
{
	using (SPWeb web = site.OpenWeb())
	{
		// code...
	}
}

 

SPSite도 위와 같은 형태로 코딩되면 됩니다~~~

 

감사합니다.


 

타이머 잡 디버깅 방법...

 

가장 잘 성명되어 있는 곳은 역시 MSDN입니다.

http://msdn.microsoft.com/en-us/library/ff798310.aspx

 

간단하게 과정을 설명하면 아래와 같습니다.

  1. 해당 프로젝트를 연다.
  2. 프로세스를 OWSTIMER.exe 로 연결한다.
  3. Breakpoint를 Execute method에 건다.
  4. 중앙관리로 가서 모니터링(Monitoring) –> 작업 정의 검토(Review job definitions)로 간다.
  5. 해당 타이머잡을 찾아서 선택하고.. 지금 실행(Run Now)를 선택하여 실행한다.
  6. 그러면 걸린다...

 

중요한 부분은 역시 프로세스 연결인데요..

연결해야 하는 프로세스가 w3c.exe가 아닌 OWSTIMER.EXE로 연결하셔야 합니다.

 

그리고 중앙 관리의 모니터링 –> 작업정의 검토로 가시면 됩니다.

 

그런 다음 지금 실행~~

 

감사합니다...


사이트 정의나 리스트 정의 그리고 Event Receiver 등을 만들게 되면..

Feature가 생성 됩니다.

 

이때 Feature의 범위가 지정되는데요..

Farm, WebApplication, Site, Web 중 하나로 만들어 집니다.

어떤 요소가 어떤 범위에 해당하는지 MSDN에 잘 나와있어서 작성하게 되었습니다.

 

확인은 아래 링크에서 하시면 되고요..

http://msdn.microsoft.com/en-us/library/ms474383.aspx

 

Feature 범위 순은 아래와 같습니다.

Farm Control
Custom Action
Custom Action Group
Feature/Site Template Association
Hide Custom Action 
WebApplication Control
Custom Action
Custom Action Group
Document Converter
Feature/Site Template Association
Hide Custom Action 
Site Content Type
Content Type Binding
Control
Custom Action
Custom Action Group
Feature/Site Template Association
Field
Hide Custom Action
List Instance
Module
Workflow
Web Control
Custom Action
Custom Action Group
Hide Custom Action
List Instance
List Template
Module
Receiver

 

 

감사합니다.


 

오늘은 쉐어포인트 파워쉘 코드를 생성해주는 생성기가 있어서 소개하고자 합니다.

해당 경로는 아래를 이용하시면 됩니다.

http://www.microsoft.com/resources/TechNet/en-us/Office/media/WindowsPowerShell/WindowsPowerShellCommandBuilder.html

1, 2번의 항목을 3번으로 드레그 하면 파워쉘 코드를 생성해 주시는 것입니다.

 

 

해당 코드는 Copy to Clipboard를 선택하시면 자동 복사가 됩니다.

상단에 보시면 Product에서 Shareponit server, foundation, Office 365용 코드를 생성할 수 있습니다.

 

그리고 위의 페이지는 실버라이트로 되어 있으며...

로컬에 바로 설치도 가능합니다.

 

설치 방법은 해당 페이지에서 마우스 우클릭하여 설치를 선택하시면 로컬에 설치가 되며, 바로 사용할 수 있습니다.

 

 

 

이렇게 사용할 수 있으니 한번 해 보세요.

오프라인에서는 안될 것 같은데.. 잘 모르겠습니다~

 

감사합니다.

 

Sharepoint에서 에러가 발생되면 아래와 같은 화면에 출력 됩니다.

 

 

위 메시지 확인 방법은 아래 링크에서 확인 할 수 있습니다.

 
2012/01/05 - [Developer/Troubleshoot] - Sharepoint Exception Message(Error 로그) 확인 하는 방법 [부제:예기치 않은 오류가 발생했습니다.]


만약 서버가 아닌 개발용 피시에서는 이런 메시지보다 직관적인 에러 메시지가 필요합니다.

해당 메시지 출력 방법으로 가장 간단한 방법은 VS2010에서 F5를 눌러 디버깅 모드로 배포하게 되면 Web.config 파일을 수정하여 디버깅 모드로 볼 것이냐고 물어봅니다.

 

예를 하여 디버깅 모드로 들어가면 가장 빨리 메시지를 확인 할 수 있으며, 간단합니다.

 

하지만 이 방법이 아닌 직접 Web.config 파일을 수정하는 방법은 아래와 같습니다.

 

바꿀 곳은 먼저 IIS root의 해당 어플리케이션 경로의 Web.config 파일입니다.

 

C:\inetpub\wwwroot\wss\VirtualDirectories\frm.dev.com80\web.config

 

위의 경로에 파일을 수정합니다.

 

그리고 아래와 같이 응용프로그램 페이지로 만든 경우에는 아래의 경로에서 변경하셔야 됩니다.

 

 

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\web.config

 

오늘은 IIS에 배포된 application의 web.config 파일을 수정하는 방법을 진행하도록 하겠습니다.

 

먼저 CallStack 추적 방법입니다.

 

  <SharePoint>
    <SafeMode MaxControls="200" CallStack="false" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">
      <PageParserPaths>
      </PageParserPaths>
    </SafeMode>

<!-- 아래와 같이 변경합니다. -->
    <SafeMode MaxControls="200" CallStack="true" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">
      <PageParserPaths>
      </PageParserPaths>
    </SafeMode>

 

 

 

그리고 customErrors, compilation 부분의 변경 내용입니다.

  <system.web>
    <customErrors mode="On" />
    <compilation batch="false" debug="false">

<!-- mode를 Off로 변경합니다. -->
  <system.web>
    <customErrors mode="On" />
    <compilation batch="false" debug="true" optimizeCompilations="true">

 

 

 

이상입니다.

 

 

이번 시간에는 쉐어포인트의 스케줄(TimerJob) 을 만들어 보도록 하겠습니다.

 

먼저 프로젝트를 만듭니다.

Sharepoint –> 빈 Sharepoint 프로젝트

 

 

팜 솔루션을 선택합니다.

 

 

그리고 JobDefinition class를 만듭니다.

 

 

저는 이름을 현재 작업 중인 업무명으로 하였습니다.

 

 

그리고 아래와 같이 직접 코딩합니다.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace HPW.Portal.JobTools.BizRequest.TimerJob
{
	public class BizRequestJobDefinition : SPJobDefinition
	{
		#region Contructor

		#region // BizRequestJobDefinition() : base() //
		public BizRequestJobDefinition()
			: base()
		{
		} 
		#endregion

		#region // BizRequestJobDefinition(string jobName, SPService service, SPServer server, SPJobLockType targetType) : base(jobName, service, server, targetType) //
		public BizRequestJobDefinition(string jobName, SPService service, SPServer server, SPJobLockType targetType)
			: base(jobName, service, server, targetType)
		{
		} 
		#endregion

		#region // BizRequestJobDefinition(string jobName, SPWebApplication webApplication) : base(jobName, webApplication, null, SPJobLockType.ContentDatabase) //
		public BizRequestJobDefinition(string jobName, SPWebApplication webApplication)
			: base(jobName, webApplication, null, SPJobLockType.ContentDatabase)
		{
			this.Title = "BizReqeust VOC Progress Timer Job";
		} 
		#endregion

		#endregion

		#region Instance Variables

		#endregion

		#region Properties

		#endregion

		#region Initialize and Shutdown methods

		#endregion

		#region Private Methods

		#endregion

		#region Override Methods

		#region // override void Execute(Guid targetInstanceId) //
		public override void Execute(Guid targetInstanceId)
		{
			// Code Here...
			//SPWebApplication webApplication = this.Parent as SPWebApplication;
			//SPContentDatabase contentDb = webApplication.ContentDatabases[targetInstanceId];

			//SPList Listjob = contentDb.Sites[0].RootWeb.Lists["ListTimerJob"];
			//SPListItem newList = Listjob.Items.Add();
			//newList["Title"] = DateTime.Now.ToString();
			//newList.Update();
		} 
		#endregion

		#endregion

		#region Event Handlers

		#endregion
	}
}

 

그리고 Feature를 생성합니다.

 

 

생성 후 이름을 변경하고 그리고 이벤트 수신기(EventReceiver)를 만듭니다.

 

 

그리고 아래와 같이 코딩.

using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;

using Microsoft.SharePoint.Administration;

namespace HPW.Portal.JobTools.BizRequest.TimerJob.Features.VOCProgressSendMail
{
	/// <summary>
	/// 이 클래스는 기능을 활성화, 비활성화, 설치, 제거 및 업그레이드하는 동안 발생하는 이벤트를 처리합니다.
	/// </summary>
	/// <remarks>
	/// 패키지하는 동안 이 클래스에 연결된 GUID를 사용할 수 있으며 수정하지 않아야 합니다.
	/// </remarks>

	[Guid("664bc876-c03e-4120-bba4-f1644c1970cb")]
	public class VOCProgressSendMailEventReceiver : SPFeatureReceiver
	{
		private const string JOB_NAME = "VOCProgressSendMail";

		public override void FeatureActivated(SPFeatureReceiverProperties properties)
		{
			SPSite site = properties.Feature.Parent as SPSite;

			// make sure the job isn't already registered
			foreach (SPJobDefinition job in site.WebApplication.JobDefinitions)
			{
				if (job.Name.Equals(JOB_NAME))
					job.Delete();
			}

			// install the job
			BizRequestJobDefinition listLoggerJob = new BizRequestJobDefinition(JOB_NAME, site.WebApplication);

			SPMinuteSchedule schedule = new SPMinuteSchedule();
			schedule.BeginSecond = 0;
			schedule.EndSecond = 59;
			schedule.Interval = 5;

			listLoggerJob.Schedule = schedule;
			listLoggerJob.Update();
		}


		// 기능이 비활성화되기 전에 발생하는 이벤트를 처리하려면 아래 메서드의 주석 처리를 제거합니다.

		public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
		{
			SPSite site = properties.Feature.Parent as SPSite;

			// delete the job
			foreach (SPJobDefinition job in site.WebApplication.JobDefinitions)
			{
				if (job.Name.Equals(JOB_NAME))
					job.Delete();
			}
		}


		// 기능이 설치된 후에 발생하는 이벤트를 처리하려면 아래 메서드의 주석 처리를 제거합니다.

		//public override void FeatureInstalled(SPFeatureReceiverProperties properties)
		//{
		//}


		// 기능이 제거되기 전에 발생하는 이벤트를 처리하려면 아래 메서드의 주석 처리를 제거합니다.

		//public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
		//{
		//}

		// 기능이 업그레이드될 때 발생하는 이벤트를 처리하려면 아래 메서드의 주석 처리를 제거합니다.

		//public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
		//{
		//}
	}
}

 

중요한 부분은 SPMinuteSchedule 입니다.

분단위 스케줄의 경우에는 위와 같은 클래스를 사용하고 아닌 경우에는 아래 클래스를 사용합니다.

시간 별 : SPHourlySchedule

일 별 : SPDailySchedule

주 별 : SPWeeklySchedule

월 별 : SPMonthlySchedule

 

그리고 해당 Feature의 범위를 Site로 수정합니다.

 

 

그리고 배포 하시면 됩니다.

 

확인은 아래와 같이 합니다.

중앙 관리 –> Monitoring –> Check job status –> Scheduled 그리고 해당 제목으로 검색하시면 찾으실 수 있습니다.

 

 

제가 스케쥴로 만든 것이 바로 아래 리스트에 제목을 입력한 것이었습니다.

아래와 같이 정상적으로 출력 되는 것을 확인 할 수 있습니다.

 

 

위의 내용은 MSDN을 참고하였습니다.

여기를 선택하여 이동하시기 바랍니다.

 

감사합니다.

 

 

App_GlobalResource 폴더에 리소스 배포하기

 

맵핑 폴더를 가지고는 할 수가 없네요.

오늘은 빈 요소를 추가하여 배포하는 방법에 대해서 알아보도록 하겠습니다.

 

순서는 아래와 같습니다.

  1. Create Empty Sharepoint Project..
  2. Add a new Empty Element SPI (Project Item)
  3. Add Resource files in Empty element
  4. Selected Resource file
  5. Change the deployment type to AppGlobalResource
  6. Project Deploy..

 

 

 

 

 

 

배포 형식을 변경해야 합니다.

 

 

 

 

<asp:Literal ID="Literal1" runat="server" Text="<%$ Resources:ResourceData, Success %>" />

 

위와 같이 사용하시면 됩니다.

 

그리고 Package Manifest의 내용은 아래와 같습니다.

<Solution xmlns="http://schemas.microsoft.com/sharepoint/" SolutionId="5d99ee06-3444-4b23-b3ea-d07fca074486" SharePointProductVersion="14.0">
  <ApplicationResourceFiles>
    <App_GlobalResourceFile Location="SharePointProject1\App_GlobalResources\ResourceData.resx" />
  </ApplicationResourceFiles>
  <Assemblies>
    <Assembly Location="SharePointProject1.dll" DeploymentTarget="WebApplication" />
  </Assemblies>
  <RootFiles>
    <RootFile Location="Resources\ResourceData.resx" />
  </RootFiles>
  <TemplateFiles>
    <TemplateFile Location="Layouts\ScriptResources\ScriptResourceData.aspx" />
    <TemplateFile Location="Layouts\SharePointProject1\v4temp.master" />
    <TemplateFile Location="Layouts\ScriptResources\GlobalResourceTest.aspx" />
  </TemplateFiles>
  <FeatureManifests>
    <FeatureManifest Location="SharePointProject1_Feature1\Feature.xml" />
  </FeatureManifests>
</Solution>

 
참고 경로는 아래와 같습니다.
AHow to: Add a Resource File
Localizing SharePoint Solutions
 

이상입니다.


 

 

asp.net에서는 aspx 페이지에 아래와 같이 작성하면 script 다국어 처리가 가능합니다.

 

ASPX

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ScriptsConstants.aspx.cs" Inherits="WebApp.Page.ScriptsConstants" %>

var INFO_SUCCESS = '<%= GetTextResource("ScriptResource", "INFO_SUCCESS")%>';
var INFO_MIGRATION_LIMIT = '<%= GetTextResource("ScriptResource", "INFO_MIGRATION_LIMIT")%>';

 

CS

protected void Page_Load(object sender, EventArgs e)
{
    try
    {
		Response.Clear();
		Response.ContentType = "text/javascript";
		Response.Expires = -1;
		Response.Buffer = true;
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

 

사용 페이지

<script language="javascript" type="text/javascript" src="/Web/Page/ScriptsConstants.aspx"></script>

 

이 부분을 Sharepoint로 변경하도록 하겠습니다.

먼저 Sharepoint에서 리소스 사용 방법입니다.

// ASPX
// Page 상단에 Utilities dll 선언
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%= SPUtility.GetLocalizedString("$Resources:ResourceData,INFO_SUCCESS", "ResourceData", (uint)System.Globalization.CultureInfo.CurrentUICulture.LCID)%>

// ASPX.CS
string strSuccess = Microsoft.SharePoint.Utilities.SPUtility.GetLocalizedString("$Resources:ResourceData,INFO_SUCCESS", "ResourceData", (uint)System.Globalization.CultureInfo.CurrentUICulture.LCID);

 

등록은 VS 2010으로 진행하도록 하겠습니다.

 

Resource 파일을 등록하기 위해서는 Shareponit resources mapping folder를 추가하고 거기에 등록하여야 합니다.

 

 

 

 

그리고 Resources 파일을 등록합니다.

 

 

그리고 값을 설정하고

 

 

그리고 ScriptResource 로 사용될 응용프로그램 페이지를 등록합니다.

 

 

당연히 Layout 폴더에 넣어야 됩니다.

 

 

그리고 작성은 위에 소스를 참고하시고 적용된 페이지는 아래와 같습니다.

 

 

여기서 중요한 부분이 상단의 Page에 MasterPageFile Property를 삭제하고 위와 같이 작성하여야 합니다.

그리고 asp.net에서 사용하던 방식처럼 script link로 연결하여 사용하시면 됩니다. 

 

이상입니다.


감사합니다.


 

 

SharePoint 2010의 경우 기본적으로 전체 넓이를 가지고 갑니다.

오늘은 전체 넓이 말고 고정 사이즈를 주고 핸들링 하는 방법에 대해서 작성합니다.

 

해당 문서는 제가 임의로 작업한 부분이라. 명확하지 않습니다.

그리고 s4-workspace 이름을 변경하여 작업하였으며, 이는 Sharepoint가 재대로 사이즈 조정을 못할 수 있음을 알려 드립니다.

 

적용 화면은 아래와 같습니다.

 

V4.master 파일을 보시면 기본적으로 아래와 같은 구조입니다.

	<body>
		<form runat="server" onsubmit="if (typeof(_spFormOnSubmitWrapper) != 'undefined') {return _spFormOnSubmitWrapper();} else {return true;}">
			...
			<div id="s4-ribbonrow" class="s4-pr s4-ribbonrowhidetitle">
				Ribbon Contents...
			</div>
			<div id="s4-workspace">
				body Contents....
			</div>
			...
		</form>
	</body>
</html>

 

위 구조에서 제가 변경한 부분은 아래와 같습니다.

css

body #ui-page-wrapper{ margin: 0px; padding: 0px; width: 900px; }
body #s4-workspace-wrapper { width:100%; overflow: auto; background-color:#999999; }
body #s4-ribbonrow-wrapper, body #s4-workspaces{text-align:left;  width: 900px; margin: 0px; padding: 0px; }
body #s4-workspaces { overflow-y:hidden; overflow-x:auto; background-color:#FFFFFF; }
body div#s4-workspace-wrapper div#s4-workspaces div#s4-titlerow { width:100%; }

javascript

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script language="javascript" type="text/javascript">

	$(document).ready(function () {
		$("div#s4-ribbonrow-wrapper").append($("body div#s4-workspace-wrapper div#s4-workspaces div#s4-titlerow"));

		setTimeout(fnSetWorkspaceHeight, 100);

		$(window).resize(function () {
			var ribbonRow = $("body div#s4-ribbonrow-wrapper");
			var workspaceRow = $("div#s4-workspace-wrapper");

			var docHeight = $("div#s4-workspaces").height() + ribbonRow.height();

			if (docHeight < $(window).height())
				$("body div#s4-workspaces").css("margin-left", "0px");
			else
				$("body div#s4-workspaces").css("margin-left", "16px");

			workspaceRow.height(($(window).height() - ribbonRow.height()) + "px");
		});
	});

	function fnSetWorkspaceHeight() {
		var ribbonRow = $("body div#s4-ribbonrow-wrapper");
		var workspaceRow = $("div#s4-workspace-wrapper");

		workspaceRow.height(($(window).height() - ribbonRow.height()) + "px");
		var docHeight = $("div#s4-workspaces").height() + ribbonRow.height();

		if (docHeight < $(window).height())
			$("body div#s4-workspaces").css("margin-left", "0px");
		else
			$("body div#s4-workspaces").css("margin-left", "16px");
	}
</script>

html

	<body>
		<form runat="server" onsubmit="if (typeof(_spFormOnSubmitWrapper) != 'undefined') {return _spFormOnSubmitWrapper();} else {return true;}">
			......
			<table width="100%">
				<tr>
					<td align="center" style="background-color:#999999;">
						<div id="s4-ribbonrow-wrapper">
							<div id="s4-ribbonrow" class="s4-pr s4-ribbonrowhidetitle">
								Ribbon Contents...
							</div>
						</div>
						<div id="s4-workspace-wrapper">
							<div id="s4-workspaces" class="s4-nosetwidth">
								body Contents....
							</div>
						</div>
					</td>
				</tr>
			</table>
			......
		</form>
	</body>
</html>

 

위 코드는 본문이 길어질 경우 스크롤 바가 생기는데 해당 스크롤 바를 문서의 좌측으로 정렬하기 위함입니다.

스크립트에서 s4-titlerow를 s4-ribbonrow-wrapper에 넣는 이유는 s4-titlerow가 본문영역에 있기 때문에 깨지는 것을 방지하기 위함입니다.

 

가로 스크롤의 경우에는 본문의 컨텐츠를 사이즈에 맞게 만들어야 되며, 일정과 같은 목록에서는 약간의 수정이 더 필요한 상태입니다.

 

전체 소스는 아래와 같습니다.

 

이상입니다.

 

 





 
Windows PowerShell compiled Help for SharePoint Server 2010

 

http://www.microsoft.com/downloads/en/details.aspx?FamilyID=045f7af5-b226-4a05-8ace-4e17cfdef856&displaylang=en

 

다운로드 후

 

 

웹 페이지가 나타나지 않는 경우에는 해당 파일의 속성에서

 

 

차단 해제를 하시고 보시면 잘 보입니다.

 

감사합니다.


+ Recent posts