Problem opening context SPSite from SPItemEventProperties - sharepoint

In the following code,
// class overrides SPItemEventreceiver
public override void ItemAdding(SPItemEventProperties properties)
{
using (var site = new SPSite(properties.SiteId)) //SiteId is GUID <<corrected
{
...
}
}
The following exception is thrown:
System.IO.FileNotFoundException: The Web application at http://URL could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.
One way to work around this is to hard-code (or configure) the URL specified in Alternate Access Mappings. Putting the correct URL in Alternate Access Mappings is ultimately the correct solution, but if possible, I need a work-around that doesn't require configuration.

SiteId should not be an integer - SPSite ctor only accepts URLs or Guids. Given that it is an GUID, I don't see how AAM plays a part here. An alternate approach might be to use:
properties.OpenWeb().Site
Also, since you are in a synchronous event handler you should have access to SPContext.Current.Site (unless you're trapping events in a document library - a long standing sharepoint bug means there is no context in sync events for doclibs - shitty)
-Oisin

Related

adding custom methods in Hook environment?

i am adding a new method into CalEventLocalServiceImpl using hook...
my code is ..
public class MyCalendarLocalServiceImpl extends CalEventLocalServiceWrapper {
public MyCalendarLocalServiceImpl(CalEventLocalService calEventLocalService) {
super(calEventLocalService);
// TODO Auto-generated constructor stub
}
public List getUserData(long userId) throws SystemException{
DynamicQuery query=DynamicQueryFactoryUtil.forClass(CalEvent.class)
.add(PropertyFactoryUtil.forName("userId").eq(userId));
List deatils=CalEventLocalServiceUtil.dynamicQuery(query);
return deatils;
}
}
liferay-hook.xml:
<service>
<service-type>
com.liferay.portlet.calendar.service.CalEventLocalService
</service-type>
<service-impl>
com.liferay.portlet.calendar.service.impl.MyCalendarLocalServiceImpl
</service-impl>
</service>
my question is how to use getUserData from jsp file.
Can anybody help me out....
i think u didn't gt my question...i want list of events based on USERID from Calendar ...to achieve this task what i need to do??
I assume getUserData() is not overridden but a new method (can't look up currently). This is not what you can do when overriding a service. Instead you'd have to add a new Service and make it available to the portal.
Remember that a customized ("hooked") jsp is running in the portal classloader, while your overloaded service is running in the hook's classloader. Thus, if you create a new service and make the service.jar available to Liferay (e.g. on the global classpath) you can call it from JSPs. The interface of Liferay services can not be extended through an overloaded service.
In case getUserData() is already in the interface (as I said I can't look up currently), you just need to call the CalendarLocalServiceUtil from your jsp and it will be delegated to your wrapper.
Just to add to Olaf's answer and comments...
if you you want to extend CalEventLocalService service with just "getUsetData" and use it in one jsp than building your own service might be overkill. Simply put your code from "getUserData" in jsp. Otherwise follow Olaf's suggestions.

Extending log4net - Adding additional data to each log

We're working on logging in our applications, using log4net. We'd like to capture certain information automatically with every call. The code calling log.Info or log.Warn should call them normally, without specify this information.
I'm looking for a way to create something we can plug into log4net. Something between the ILog applications use to log and the appenders, so that we can put this information into the log message somehow. Either into ThreadContext, or the LogEventInfo.
The information we're looking to capture is asp.net related; the request url, user agent, etc. There's also some information from the apps .config file we want to include (an application id).
I want to get between the normal ILog.Info and appender so that this information is also automatically included for 3rd party libraries which also use log4net (Nhibernate, NServiceBus, etc).
Any suggestions on where the extensibility I want would be?
Thanks
What you are looking for is called log event context. This tutorial explains how it works:
http://www.beefycode.com/post/Log4Net-Tutorial-pt-6-Log-Event-Context.aspx
In particular the chapter 'Calculated Context Values' will interesting for you.
Update:
My idea was to use the global context. It is easy to see how this works for something like application ID (in fact there you do not even need a calculated context object). Dynamic information like request url could be done like this:
public class RequestUrlContext
{
public override string ToString()
{
string url;
// retrieve url from request
return url;
}
}
The object is global but the method is called on the thread that handles the request and thus you get the correct information. I also recommend that you create one class per "information entity" so that you have a lot of flexibility with the output in the log destination.

No current context when creating a sharepoint site

I've added a feature to my onet.xml file which gets activated whenever a site gets created. However, that feature needs to know the url of the site being created. I thought I could figure that out from the current SPContext within the activation event of the feature, but when I created the site I got a null reference on SPContext.Current.
Is that to be expected, or have I done something wrong? If that is the case, does anyone have any suggestions how I can dynamically learn the URL of the site being created?
Thanks
It seems like you have created a feature receiver? They don't use SPContext but find the site they have been activated on through the properties, like so:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
using (SPWeb web = properties.Feature.Parent as SPWeb)
{...}
}

Versioning by default in SharePoint

How can I modify a SharePoint site so that versioning is turned on by default in Document Libraries?
Versioning is not done at the site level, but at the list level.
If you want versioning to be turn on on each new library, you'll have to either:
Use your own library template (with versioning turned on)
Use feature + event handler to programmatically activate versioning on each new list
The easiest way is probably to use your own template. To do this, create a new document library, activate versioning, then save this list as template.
When you create a new list, you will then be able to use your template and directly create a list with versioning activated.
You could of course create your own site definition, but that's probably not the best solution. Creating a custom library template will work too, but if you want versioning turned on for the libraries that a particular site definition creates for you, you'll have to come up with something else.
We happen to have done this for our SharePoint implementation. We decided the best way was to create an event handler feature and staple it to all sites so that when the site is created, versioning will get turned on for all existing document libraries. Of course, new document libraries would get whatever versioning options the user who created it set.
The problem we ran into is that there is no "ListCreating" event handler so we couldn't turn the versioning on at that point. So, we tried to put the code inside the FeatureActivated event handler, figuring it would be activated on site creation and then all document libraries could be changed to have versioning turned on. The problem is that this event fired before the libraries were actually created.
So instead, we decided to put the code into the "ItemAdding" event handler and remove it after the first time that it runs. So the first time a user adds a list item or a document, it will turn on versioning for all document libraries in the site. This way, we ensure there is no way for a user to add a document to an existing library without it being versioned. Additionally, any libraries that get created before an item gets added will have versioning turned on by default as well.
It was a bit of a hairy solution, but it has worked very well for us. Here's the code we used:
public class SetVersioning : SPItemEventReceiver
{
public override void ItemAdding(SPItemEventProperties properties)
{
SPWeb CurrentWeb = properties.OpenWeb();
foreach (SPDocumentLibrary doclib in CurrentWeb.GetListsOfType(SPBaseType.DocumentLibrary))
{
doclib.EnableVersioning = true;
doclib.MajorVersionLimit = 8;
//doclib.EnableMinorVersions = true;
doclib.Update();
}
//now get rid of the receiver
SPEventReceiverDefinitionCollection receivers = CurrentWeb.EventReceivers;
foreach (SPEventReceiverDefinition definition in receivers)
{
if (definition.Name.Equals(EVENT_RECEIVER_NAME))
{
definition.Delete();
break;
}
}
base.ItemAdding(properties);
}
}

SharePoint Development Permissions

Hi I am using the SharePoint namespace to pull items from various lists throughout the site. My web part works, but only on my account. When I try it on another account it gives me "Error: Access Denied" for the page. I have taken all web parts out and have only this web part on the page. When I remove the following lines the page loads for everyone, when I add it back in however it does not work. I am guessing this is some permission problem. I was wondering is there away to programatically query different lists on SharePoint by assigning a user id to use? Thank you for any help
...
SPSite site = new SPSite(_SPSite);
SPWeb eachWeb = site.AllWebs[0];
SPListItemCollection myItemCollection = eachWeb.Lists["Listings"].Items;
...
You're correct, the access denied error is occurring when you're using an account which does not have access to the "Listings" list in the current website.
The easiest way around the issue is to use a SPSecurity.RunWithElevatedPrivleges call:
SPSecurity.RunWithElevatedPrivleges(delegate()
{
//Your code here
});
which will run whatever code is contained in the anonymous method using the SharePoint/System account, granting complete control. Be careful when using this technique though, as it equivalent to running code at full trust with a super user account. There are other caveats to be aware of as well.
Try:
SPWeb eachWeb = SPContext.Current.Site.RootWeb.Webs[0];
SPListItemCollection myItemCollection = eachWeb.Lists["Listings"].Items;
Remember that SPWeb should be used in a using block, or disposed of explicitly after use.
As regards the first caveat from EvilGoatBob, I quote:
"If you're manipulating any Object Model elements within your elevated method, you need to get a fresh SPSite reference inside this call. For example
SPSecurity.RunWithElevatedPrivileges(delegate(){
SPSite mySite = new SPSite(http://sharepoint/);
SPWeb myWeb = SPSite.OpenWeb();
// further implementation omitted
});"
Notice that the site parameter is hard-coded - this is because of a bug. If you instead had tried:
using (SPSite site = new SPSite("http://" + System.Environment.MachineName)) {}
You would get the rather generic "No SharePoint Site exists at the specified URL..." error. This caused me no end of grief. Bottom line is that you have to hard-code the server name (unless anyone has an alternative). You can also get a similar error message when debugging Web Parts for the first time with VSeWSS 1.3.
You do not need to hardcode the server name in this case because your requirement is to retrieve items from list inside the same site as your webpart. You are correct, if you do not have enough privileges with your account, then you get the Access Denied. The solution is to create a new SPSite object within a different security context, and do your work:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(SPContext.Current.Site.Url))
{
using (SPWeb web = site.OpenWeb())
{
//the web object was retrieved with elevated privileges under the system account.
//do your work here:
SPListItemCollection myItemCollection = web.Lists["Listings"].Items;
//...
}
}
}
);
With the code above, your webpart is portable because there's no hardcoding, and runs in the correct security context while disposing of all unmanaged SPRequest objects created by the SPSite and SPWeb constructors.

Resources