Slow Performance in Excel Addin (C#/ExcelDna) - excel

We have an Excel Addin developed in C# and integrated with ExcelDna.
It worked fine for many years.
But now for one customer it runs with slow performance.
I added some logging and can't figure out any significant slow part in the code.
It seems that in general every piece of code is a bit slower and for longer running tasks the total loss of time is significant.
The Addin runs in its own AppDomain and because of some Nuget dependencies, we use AssemblyRedirects specified in the config file of the Addin, which is used by the AppDomain.
And now the funny/weird finding:
My colleague added those Redirects to the Excel.exe.config and voila: it runs fast.
What the heck is going on here?
Well, it kinda fixed the problem, but of course we don't wanna manipulate the config file of Excel.
We figured out, that if only one of these two redirects exist in the Excel.exe.config, the Addin runs fast:
<dependentAssembly>
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0"/>
</dependentAssembly>
Any help on that is appreciated.

Related

How do I handle long running jobs in Azure App Service?

I am rather new to hosting in Azure. I have a .net 4.6 Web app, running in Azure as an App Service.
The solution contains some actions, that run for a long time. These get stopped after a 230 seconds timeout, which seems to be an Azure-thing.
I learned that I should place this code in an Azure Function in order to have it running as a background job. Here there should not be a timeout, as long as I don't use the Consumption plan.
I also use Azure Storage in my solution.
My problem is that if I use Azure Functions v1 (NuGet Microsoft.NET.Sdk.Functions v1.0.24), I am forced to use Newtonsoft.Json version =9.0.1
Meanwhile NuGet WindowsAzure.Storage requires Newtonsoft.Json version >=10.0.2
That breaks for me.
Then I tried out Azure Functions v2. But it only supports .Net Core, which is not an option for me in this project.
My main issue is still to find a way to be able to run these long running tasks.
One way could be to break the job into smaller parts, but in this case, I would like to be handle it in the same request.
Check that you do not have a timeout configured in your hosts.json.
"functionTimeout": "00:05:00"
The full configuration options for V1 and V2 are documented here.
In consumption plan, the maximum timeout is 10 minutes. In an app service plan it can be indefinite (but it makes sense to put a cap in, even if it is just 1 or 2 hours).
If you want to break up your functionality, you may find a suitable Durable Functions pattern.
On your Newtonsoft conflict, see if you can address this using a binding redirect.
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30AD4FE6B2A6AEED" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-9.9.0.0" newVersion="10.0.2.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>

Added reference to System.Web.WebPages 3.0 immediately changes to 2.0

Summary: I have ONE project in a solution that I can't point to WebPages 3.0 (or Helpers 3.0). The others are fine, but one just immediately resolves to the Program Files x86 2.0 assembly.
Background: I have an MVC app that I inherited. I've done a few updates to it, bringing it up to MVC-3 in the last iteration. To cut to the chase, I've found myself in an unexpected bind that's seemed to snowball through my attempted fixes.
I always strive for binary deployments, eliminating the need to install packages on the build server and the web servers. Therefore, I had MVC/ASP.Net WePage binaries in the solution tree with references to those local copies.
What I've changed: Believe it or not, I've never messed with NU GET, and decided to give it a whirl. I removed all my local binaries (2x, 3x, 100x checked to make sure) and added MVC 5 and its dependencies. This seems great because I can eliminate my home-grown binary pattern in favor of the packages that are stored under the solution tree on disk/TFS. I also figured I might as well point all projects to the latest 4.5 FW.
Problems: On compilation VS is complaining that I have v2 and v3 of the mentioned DLL, but I have no references to v2. Also, before even compiling, if I remove the reference and re-add it (pointing to the package lib content) it immediately comes in as v2.0 and the resolved folder is the x86 v2 instance.
While trying to resolve this I've removed the packages and reinstalled them several times to no avail.
I've also tried adding a binding redirect to we.config, but I suspect that's a runtime thing? I have a number of other projects in this solution, all of which are fine, pointing to 3.0!
I've used reflector to look at the references for all the assemblies in the bin folder, thinking I'd find something pointing to pages 2.0, but I don't.
Looking in the csproj file I see the version hard-coded to 2.0 in the Include. I changed it to 3.0 and when I reload the solution it's reverted to 2.0. Argh!
I've closed and reloaded the solution a hundred times. I've cleaned it 1,000 times. I've manually removed the obj/bin folders multiple times.
I just don't know how else to debug this!
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\..\packages\Microsoft.AspNet.WebPages.3.0.0\lib\net45\System.Web.Helpers.dll</HintPath>
</Reference>
I found a second Include in the csproj for WebPages and Helpers! I have no idea how they got there. Uninstalling the NUGET packages would remove the FIRST reference, but not the second. To add to the frustration the second reference specified no version or location. Adding a version and location specific reference (NUGET or manually) would be overridden immediately with the GAC version!

Webpart "Not registered as safe" after changing AssemblyVersion

I (successfully) deployed some sharepoint2010 - Webparts using msbuild. Everything works fine until I decided to change the assemblyVersion. Whenever I do that the message
Web Part Error: A Web Part or Web Form Control on this Page cannot be displayed or imported.
The type RTContacts, RTContacts,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=2721ba85ef1e4b88 could not be found or it is not registered as safe.
A solution would be to stay on 1.0.0.0, but there should be a better way...
Perhaps interesting to mention is that we use a centralized AssemblyFile which is included as a link.
The manifest contains the correct assemblyversion:
<Assemblies>
<Assembly Location="RTContacts.dll" DeploymentTarget="GlobalAssemblyCache">
<SafeControls>
<SafeControl Assembly="RTContacts, Version=1.0.4325.18399, Culture=neutral, PublicKeyToken=2721ba85ef1e4b88" Namespace="RTContacts" TypeName="*" />
</SafeControls>
</Assembly>
When I add the WebPart again to that Site, it is displayed correctly, but already existing webParts seem to link to the old version.
You are having these problems because you're using the versioning attributes incorrectly.
If you examine, for example, Microsoft.SharePoint.dll in Reflector you will see v14.0.0.0 (for SharePoint 2010).
This AssemblyVersion will stay exactly the same for Beta, RCx, RTM all service packs and CU's etc - the only thing that changes is the AssemblyFileVersion (this is the thing you see in Windows Explorer under properties)
See this for more details
SharePoint features: How can I use wildcard assembly versioning?
But don't take my word for it - Microsoft KB556041 - How to use Assembly Version and Assembly File Version
If you follow this then no Assembly binding redirections are necessary and when you update your web part the existing instances will not be broken.
Original question: How to fix the "Not registered as safe" error after the assembly version has been changed?
Web Parts are registered as safe in the web.config files.
Appropriate entry looks like this:
<SafeControl Assembly="MyWebPartLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
Namespace="MyWebPartLibrary"
TypeName="*"
Safe="True"
AllowRemoteDesigner="True"/>
Modify the Assembly attribute and replace the old version number with a new one.
Current question: How can I change assembly version without having to re-add all the Web Parts to the page?
I think you'll need to use assembly redirection to keep existing Web Part instances working:
<runtime>
<assemblyBinding>
<dependentAssembly>
<assemblyIdentity name="RTContacts" publicKeyToken="2721ba85ef1e4b88" culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0" newVersion="1.0.4325.18399" />
</dependentAssembly>
</assemblyBinding>
</runtime>
Read the article Web Part Versioning with assembly redirection for a detailed analysis of this problem.

Add a bindingRedirect to the web.config declaratively in SharePoint 2007

It is possible to add keys to the web.config by creating a file: 12/CONFIG/webconfig.name.xml
(See http://msdn.microsoft.com/en-us/library/ee413929.aspx)
With contents:
<actions>
<add path="configuration/SharePoint/SafeControls">
<SafeControl
Assembly="CustomWebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=123456789abcdefgABC"
Namespace="CustomWebPart"
TypeName="*"
Safe="True" />
</add>
<add path="configuration/runtime/assemblyBinding">
<dependentAssembly>
<assemblyIdentity name="CustomWebPart" publicKeyToken="123456789abcdefgABC" culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
</actions>
This works great for adding safe controls, but it doens't seem to work for assembly redirects. Does anyone have an idea why this doens't work? Is it maybe the case only tags inside "configuration/SharePoint/" can be added?
You can't add binding redirects on deployment with configuration files in SharePoint 2007 (though you can in 2010) so you would have to write code to do this using SPWebConfigModification.
Beware though its not easy - just search on SPWebConfigModification and check out the first page of results.
As an alternative I've got to ask why you might want to do this - if this is just versioning minor changes (i.e. v1.1 > v1.2) then perhaps this is not the best way to do this - check out file assembly versioning instead.

Specifying the location of an assembly to II

My ASP.NET application uses some 3rd assembly. What are my options to make the application load that assembly? Do I have to put it in the GAC?
I don't want to modify the machine's PATH env variable...
You can put it into your application folder (best solution) or add a codebase tag in your web config like explained in this msdn entry:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="MyAssembly2" culture="neutral" publicKeyToken="307041694a995978"/>
<codeBase version="1.0.1524.23149" href="FILE://C:/Myassemblies/MyAssembly2.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Add it to the GAC only if you want to share that assembly.
Is your assembly strongly named?
You can either put it in the GAC or reference it in your web.config (using a <codeBase> element according to this MSDN article.
If not
The assembly has to live in the bin folder of your web application.

Resources