Feature deactivation code behind in Sandbox solution - c#

Just a question to clarify my doubts here !
I created a Sandbox solution with Visual Studio 2010 for SharePoint 2010.
Solution contains just a list instance, and when the feature is deployed a list gets created on the site.
Now, I also wish to delete the list when the feature is deactivated.
For which I wrote below code in EventReceiver.cs.
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
using (SPSite site = new SPSite("http://sitecollection"))
{
SPWeb web = site.RootWeb;
SPList list = web.Lists["listname"];
list.Delete();
list.Update();
web.Update();
}
}
While this does delete the list on feature deactivation, my question is,
How come this project is STILL a sandbox solution (no dll deployment to GAC) as it contains server-side & and a code behind file?
Thanks,
Tushar

Sandbox solutions can use server side code. The difference is that the code runs in separate windows service on server and not in w3wp process or owstimer. The cost is that you do not have access to all server side functionality (you cannot deploy timer jobs using sandbox solutions for example). You can read more about sandbox solutions here.

Related

VS2013 publish Web deployment task failed The file is in use

I am using VS2013 Premium to publish a site to Windows Server 2012.
All files publish ok except these:
SqlServerTypes\x64\msvcr100.dll
SqlServerTypes\x64\SqlServerSpatial110.dll
SqlServerTypes\x86\msvcr100.dll
SqlServerTypes\x86\SqlServerSpatial110.dll
I get this kind of errors for each of the above files I tried to publish:
Web deployment task failed. (The file 'msvcr100.dll' is in use. Learn more at: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_FILE_IN_USE.)
Interrestingly, these files were published the first time (when they were not on the server), then they are no longer overwritten. Tried with 2 different web servers.
I have followed the guide here:
http://blogs.msdn.com/b/webdev/archive/2013/10/30/web-publishing-updates-for-app-offline-and-usechecksum.aspx
...But it only managed to put the site offline (VS is placing the app_offline.htm) but publish still fails with the same error.
All other files publish perfectly.
Any ideas?
You can take you app offline during publishing which hopefully should free up the lock on the file and allow you to update it.
I blogged about this a while back. The support outlined was shipped inside of the Azure SDK and Visual Studio Update. I don't remember the exact releases but I can find out if needed. Any update dating around/after that blog post should be fine.
Prerequisites:
VS 2012 + VS update / VS 2013 + VS Update / VS2015
MSDeploy v3
Note: if you are publishing from a CI server the CI server will need the updates above as well
Edit the publish profile
In VS when create a Web Publish profile the settings from the dialog are stored in Properties\PublishProfiles\ as files that end with .pubxml. Note: there is also a .pubxml.user file, that file should not be modified
To take your app offline in the .pubxml file add the following property.
<EnableMSDeployAppOffline>true</EnableMSDeployAppOffline>
Notes
ASP.NET Required
The way that this has been implemented on the MSDeploy side is that an app_offline.htm file is dropped in the root of the website/app. From there the asp.net runtime will detect that and take your app offline. Because of this if your website/app doesn't have asp.net enabled this function will not work.
Cases where it may not work
The implementation of this makes it such that the app may not strictly be offline before publish starts. First the app_offline.htm file is dropped, then MSDeploy will start publishing the files. It doesn't wait for ASP.NET to detect the file and actually take it offline. Because of this you may run into cases where you still run into the file lock. By default VS enables retrys so usually the app will go offline during one of the retrys and all is good. In some cases it may take longer for ASP.NET to respond. That is a bit more tricky.
In the case that you add <EnableMSDeployAppOffline>true</EnableMSDeployAppOffline> and your app is not getting taken offline soon enough then I suggest that you take the app offline before the publish begins. There are several ways to do this remotely, but that depends on your setup. If you only have MSDeploy access you can try the following sequence:
Use msdeploy.exe to take your site offline by dropping app_offline.htm
Use msdeploy.exe to publish your app (_make sure the sync doesn't delete the app_offline.htm file_)
Wait some amount of time
Publish the site
Use msdeploy.exe to bring the app online by deleting app_offline.htm
I have blogged how you can do this at http://sedodream.com/2012/01/08/howtotakeyourwebappofflineduringpublishing.aspx. The only thing that is missing from that blog post is the delay to wait for the site to actually be taken offline. You can also create a script that just calls msdeploy.exe directly instead of integrating it into the project build/publish process.
I have found the reason why the solution at
http://blogs.msdn.com/b/webdev/archive/2013/10/30/web-publishing-updates-for-app-offline-and-usechecksum.aspx
did not work for the original poster, and I have a workaround.
The issue with the EnableMSDeployAppOffline approach is that it only recycles the app domain hosting the application. It does not recycle the app pool worker process (w3wp.exe) which the app domain lives in.
Tearing down and recreating the app domain will not affect the Sql Server Spatial dlls in question. Those dlls are unmanaged code which are manually loaded via interop LoadLibray calls. Therefore the dlls live outside the purview of the app domain.
In order to release the files locks, which the app pool process puts on them, you need to either recycle the app pool, or unload the dlls from memory manually.
The Microsoft.SqlServer.Types nuget package ships a class which is used to load the Spatial dlls called SqlServerTypes.Utilities. You can modify the LoadNativeAssemblies method to unload the unmanaged dlls when the app domain is unloaded. With this modification when msdeploy copys the app_offline.htm the app domain will unload and then unload the managed dlls as well.
[DllImport("kernel32.dll", SetLastError = true)]
internal extern static bool FreeLibrary(IntPtr hModule);
private static IntPtr _msvcrPtr = IntPtr.Zero;
private static IntPtr _spatialPtr = IntPtr.Zero;
public static void LoadNativeAssemblies(string rootApplicationPath)
{
if (_msvcrPtr != IntPtr.Zero || _spatialPtr != IntPtr.Zero)
throw new Exception("LoadNativeAssemblies already called.");
var nativeBinaryPath = IntPtr.Size > 4
? Path.Combine(rootApplicationPath, #"SqlServerTypes\x64\")
: Path.Combine(rootApplicationPath, #"SqlServerTypes\x86\");
_msvcrPtr = LoadNativeAssembly(nativeBinaryPath, "msvcr100.dll");
_spatialPtr = LoadNativeAssembly(nativeBinaryPath, "SqlServerSpatial110.dll");
AppDomain.CurrentDomain.DomainUnload += (sender, e) =>
{
if (_msvcrPtr != IntPtr.Zero)
{
FreeLibrary(_msvcrPtr);
_msvcrPtr = IntPtr.Zero;
}
if (_spatialPtr != IntPtr.Zero)
{
FreeLibrary(_spatialPtr);
_spatialPtr = IntPtr.Zero;
}
};
}
There is one caveat with this approach. It assumes your application is the only one running in the worker process that is using the Spatial dlls. Since app pools can host multiple applications the file locks will not be released if another application has also loaded them. This will prevent your deploy from working with the same file locked error.
There are known issues with IIS and file-locks (why they aren't solved yet i dont know).
The question i want to ask however is if you even need to re-deploy these files?
I recognize the file-names and recall them to be system-files which should either already be present on the server or simply not need to be re-deployed.
I am not very experienced when it comes to IIS but i have ran into this problem before and several of my more experienced co-workers have told me that this is as i said a known IIS-issue and i believe the answer to your question is:
Avoid deploying unnecessary files.
try again
Reset website
try again
iisreset
I think what would be the easiest thing to do is to make these dll's as CopyLocal as true. I am assuming these dll's are pulled out from program files folder. Try marking them as copylocal true and do a deployment.Try to stop any IIS local process running in your local machine.
Watch out you don't have one of those new-fangled cloud backup services running that is taking file locks - and also you don't have things open in explorer or a DLL inspection tool.
I think it's kind of ridiculous that MS doesn't make better provisions for this problem. I find that 9 times out of 10 my deployment works just fine, but then as our traffic increases that can become 1 in 10 times.
I am going to solve the problem with :
two applications MySite.A and MySite.B, where only one is running at a time.
I always then deploy to the dormant site.
If there's a problem during the deployment it will never cause the whole site to go down.
If there's a major problem after deployment you can revert back very easily.
Not quite sure how I'm implementing it, but I think this is what I need to do.

Code deleted but still outputting

I have removed several functions from my Codebehind .aspx.cs page. However the webpages are still calling the functions even though I do not call them nor to the functions actually exist anymore.
The code is working exactly like it did prior to removal...I have no idea what is going on.
Things I have tried:
Navigated to the pages using different computers and browsers.
Restarted IIS Services
Restarted IIS Application Pool for Website
Searched entire project for code that is being called
Cleaning ASP.NET Cache using following code:
public void ClearApplicationCache()
{
List<string> keys = new List<string>();
// retrieve application Cache enumerator
System.Collections.IDictionaryEnumerator enumerator = Cache.GetEnumerator();
// copy all keys that currently exist in Cache
while (enumerator.MoveNext())
{
keys.Add(enumerator.Key.ToString());
}
// delete every key from cache
for (int i = 0; i < keys.Count; i++)
{
Cache.Remove(keys[i]);
}
}
Environment
ASP.NET 2.0
IIS 6
Windows Server 2003
XP / 7 to browse (Chrome/IE)
Is the code cached somewhere?? I am rendered clueless.
In order for changes to take effect you must recompile your code and redeploy. Looks like you did not replace the DLLs.
You can read more about it here:
Web Application Projects versus Web Site Projects - See Compilation part.

How to use ServerManager to read IIS sites, not IIS express, from class library OR how do elevated processes handle class libraries?

I have some utility methods that use Microsoft.Web.Administration.ServerManager that I've been having some issues with. Use the following dead simple code for illustration purposes.
using(var mgr = new ServerManager())
{
foreach(var site in mgr.Sites)
{
Console.WriteLine(site.Name);
}
}
If I put that code directly in a console application and run it, it will get and list the IIS express websites. If I run that app from an elevated command prompt, it will list the IIS7 websites. A little inconvenient, but so far so good.
If instead I put that code in a class library that is referenced and called by the console app, it will ALWAYS list the IIS Express sites, even if the console app is elevated.
Google has led me to try the following, with no luck.
//This returns IIS express
var mgr = new ServerManager();
//This returns IIS express
var mgr = ServerManager.OpenRemote(Environment.MachineName);
//This throws an exception
var mgr = new ServerManager(#"%windir%\system32\inetsrv\config\applicationhost.config");
Evidently I've misunderstood something in the way an "elevated" process runs. Shouldn't everything executing in an elevated process, even code from another dll, be run with elevated rights? Evidently not?
Thanks for the help!
Make sure you are adding the reference to the correct Microsoft.Web.Administration, should be v7.0.0.0 that is located under c:\windows\system32\inetsrv\
It looks like you are adding a reference to IIS Express's Microsoft.Web.Administraiton which will give you that behavior
Your question helped me find the answer for PowerShell, so if the Internet is searching for how to do that:
$assembly = [System.Reflection.Assembly]::LoadFrom("$env:systemroot\system32\inetsrv\Microsoft.Web.Administration.dll")
# load IIS express
$iis = new-object Microsoft.Web.Administration.ServerManager
$iis.Sites
# load IIS proper
$iis = new-object Microsoft.Web.Administration.ServerManager "$env:systemroot\system32\inetsrv\config\applicationhost.config"
$iis.Sites
CAUTION! Using this approach we have seen seemingly random issues such as "unsupported operation" exceptions, failure to add/remove HTTPS bindings, failure to start/stop application pools when running in IIS Express, and other problems. It is unknown whether this is due to IIS being generally buggy or due to the unorthodox approach described here. In general, my impression is that all tools for automating IIS (appcmd, Microsoft.Web.Administration, PowerShell, ...) are wonky and unstable, especially across different OS versions. Good testing is (as always) advisable!
EDIT: Please also see the comments on this answer as to why this approach may be unstable.
The regular Microsoft.Web.Administration package installed from NuGet works fine. No need to copy any system DLLs.
The obvious solution from the official documentation also works fine:
ServerManager iisManager = new ServerManager(Environment.SystemDirectory + #"inetsrv\config\applicationHost.config");
This works even if you execute the above from within the application pool of IIS Express. You will still see the configuration of the "real" IIS. You will even be able to add new sites, as long as your application runs as a user with permission to do so.
Note, however that the constructor above is documented as "Microsoft internal use only":
https://msdn.microsoft.com/en-us/library/ms617371(v=vs.90).aspx
var iisManager = new ServerManager(Environment.SystemDirectory + "\\inetsrv\\config\\applicationhost.config");
This works perfectly. No need to change any references

Sharepoint cannot see newly deployed features and will not activate them

I've been updating a SP2010 solution which integrates an external content source into search via BCS. This solution deploys a feature (featureA) to the farm scope. I split it into two features, one (FeatureA) deploying to the farm scope, and one (featureB) to the site scope.
My update script does this:
Deactivate FeatureA on the farm
Update-SPSolution with the new wsp file (same name)
Activate FeatureA on the farm
Activate FeatureB on the two sites (on two different web apps)
The script bombs on the last two steps, saying
Enable-SPFeature : The Feature is either not found or not a Farm Level Feature. Use Url parameter to specify the scope of the Feature.
for the first one (farm), and
Enable-SPFeature : The Feature is not a Farm Level Feature and is not found in a Site level defined by the Url http://url-site
on the second one (sites)
This is a test run on the CI server, which means it will also crash on the production server.
However, deploying the package on my machine, and activating the features, works fine.
I've checked, the features are actually present in the SharePoint folder, so the deployment seems to have gone ok. I can't work out why SharePoint can't see them though. If I run Get-SPFeature, they are not in the list.
I've tried iisreset, to no avail.
EDIT:
I've managed to get SharePojnt to notice the two features, by using Install-SPFeature.
However, it still won't enable FeatureB, but errors out with:
Enable-SPFeature : Attempted to perform an unauthorized operation.
I'm at a bit of a loss once again.
You cannot use Update-SPSolution when new files have been added to the solution package.
From Update-SPSolution:
The Update-SPSolution cmdlet upgrades a deployed SharePoint solution in the farm. Use this cmdlet only if a new solution contains the same set of files and features as the deployed solution. If files and features are different, the solution must be retracted and redeployed by using the Uninstall-SPSolution and Install-SPSolution cmdlets, respectively.
For more information, see Adding Features during Solution Update

Remote Upload Sharepoint programatically using C#

Is it possible to remotely upload files using a Windows Application (C#) to Sharepoint Server?
Thank you.
Yes, although you may need some of the SharePoint assemblies on the "remote" machine in order to achieve what you need.
Uploading files using Client Object Model in SharePoint 2010 is a pretty good starting point for SharePoint 2010.
In case you are using the 2007 version (WSS 3.0), you can find a great summary of different ways to upload files on this link: http://vspug.com/smc750/2009/05/19/uploading-content-into-sharepoint-let-me-count-the-ways/
You must be very careful if your farm is 32bit, in that case it is very easy to use up all the available memory in the w3wp.exe process if you're uploading large files or many files in parallel, especially if the farm is a busy one. In that case you might want to use the RPC interface described in the link above, since this is the only one where you can upload files in chunks. With all other ways the entire file being uploaded must first be loaded in the w3wp's memory before it's committed to the SharePoint list item.
For ways that involve SharePoint object model, you might want to write your own web service facade to enable the clients that do not have SharePoint dlls to upload files (+ metadata if you need it).
You can use the client object model in sp2010, rather than talking to the web services directly.
Taken from my upload profile picture applications:
http://spc3.codeplex.com/SourceControl/changeset/view/57957#1015709
using (ClientContext context = new ClientContext(siteurl)) {
context.AuthenticationMode = ClientAuthenticationMode.Default;
List list = context.Web.Lists.GetByTitle(listname);
context.Load(list);
context.Load(list.RootFolder);
context.ExecuteQuery();
string url = siteurl.CombineUrl(list.RootFolder.ServerRelativeUrl).CombineUrl(listfolder).CombineUrl(name);
FileCreationInformation fci = new FileCreationInformation();
fci.Content = data;
fci.Overwrite = true;
fci.Url = url;
Microsoft.SharePoint.Client.File file = list.RootFolder.Files.Add(fci);
context.ExecuteQuery();
}
I wrote a tool available as a NuGet package in Visual Studio called SharePoint.DesignFactory.ContentFiles. With this tool you can manage all files with metadata to be uploaded to the SharePoint content database. You can use this for SharePoint 2007 (currently have to work on the SharePoint machine itself) or for SharePoint 2010 and Office 365. In this case you can work from a machine without SharePoint installed. See http://weblogs.asp.net/soever/archive/tags/SharePoint.DesignFactory.ContentFiles/default.aspx for blogposts on the tooling.

Categories

Resources