TFS SDK assembly error after moving code - asp.net

We recently did some code reorganization for our ASP.NET web site solution and I've run into an unfriendly issue with the TFS 2010 SDK assemblies that I haven't been able to figure out.
We have a small class (I included the functions using TFS SDK below) that retrieves all the TFS changeset comments since the last time we deployed the website. The web site project has the following references to use the TFS SDK:
Microsoft.TeamFoundation.Client
Microsoft.TeamFoundation.VersionControl.Client
The class used to live in the App_Code folder of the project and the following TFS assemblies were deployed in the bin folder of the site:
Microsoft.TeamFoundation.Client.dll
Microsoft.TeamFoundation.Common.dll
Microsoft.TeamFoundation.Common.Library.dll
Microsoft.TeamFoundation.dll
Microsoft.TeamFoundation.VersionControl.Client.dll
Microsoft.TeamFoundation.VersionControl.Common.dll
This worked properly with no errors when deployed to the site.
We moved this class (along with several others) into a separate class library and removed it from the App_Code folder of the site, changing all appropriate assembly references in Visual Studio for the projects. Now when it is deployed, we get the following error on any page we hit on the site:
Could not load file or assembly 'Microsoft.TeamFoundation.WorkItemTracking.Client.Cache, Version=10.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. An attempt was made to load a program with an incorrect format.
I can run from my localhost and development workspace without any issues, so something with the build seems to be amiss. After examining the build that TFS pumped out, three more assemblies are being included in the build for the TFS SDK that weren't there before:
Microsoft.TeamFoundation.WorkItemTracking.Client.Cache.dll
Microsoft.TeamFoundation.WorkItemTracking.Client.DataStore.dll
Microsoft.TeamFoundation.WorkItemTracking.Client.RuleEngine.dll
I can't figure out why these are being pulled into the build now. We don't directly reference these assemblies in any project. The code for pulling the comments from TFS didn't change, only it's assembly location. No TFS upgrades were performed. Bottom line - we added a class library where the code now lives and it seems to want some other assemblies that it didn't want before when it lived in the App_Code folder. My best guess is that TFS pulls these in as dependent assemblies for the others during the build, but I'm not sure why.
Hits online for similar errors generally revolve around 32/64 bit issues. I checked Config Manager and all the projects in the solution are set to use Any CPU, which seems right to me, and we have 32-bit applications enabled in IIS on the server.
My apologies for the length of this post, but I wanted to provide what I thought were the pertinent details. Any thoughts would be greatly appreciated. Thanks.
Public Function GetChangesSinceDeployDate(ByVal lastDeployDate As DateTime) As List(Of TFSChange)
Dim tfs As New TfsTeamProjectCollection(New Uri("http://tfs.proviadoor.com:8080/tfs/entrylink"))
tfs.EnsureAuthenticated()
Dim vcs As VersionControlServer = CType(tfs.GetService(GetType(VersionControlServer)), VersionControlServer)
Dim versionFrom As VersionSpec = GetDateVSpec(lastDeployDate)
Dim versionTo As VersionSpec = GetDateVSpec(Now)
_changeList = New List(Of TFSChange)
Dim changeSetIds As String = ""
For Each projectPath As String In _projectPaths
Dim results As IEnumerable = vcs.QueryHistory(projectPath, VersionSpec.Latest, 0, RecursionType.Full, "", versionFrom, versionTo, Integer.MaxValue, False, True)
For Each chgSet As Changeset In results
If Not chgSet.ChangesetId.ToString().InList(changeSetIds) Then
_changeList.Add(New TFSChange(chgSet.ChangesetId, chgSet.Committer, chgSet.CreationDate, chgSet.Comment))
changeSetIds.Append(chgSet.ChangesetId.ToString(), ",")
End If
Next
Next
Dim sortedList = From chg As TFSChange In _changeList _
Select chg _
Order By chg.CommitUser, chg.ChangeDate Descending
Return sortedList.ToList()
End Function
Private Function GetDateVSpec(ByVal versionDate As DateTime) As VersionSpec
Dim dateSpec As String = String.Format("D{0:yyy}-{0:MM}-{0:dd}T{0:HH}:{0:mm}", versionDate)
Return VersionSpec.ParseSingleSpec(dateSpec, "")
End Function

The message "program with an incorrect format" does suggest a 32/64-bit issue.
The problem is that "Any CPU" code will launch in the highest bit-ness it can: in your case, 64-bit, because all of the assmemblies referenced at launch time are 64-bit (or at least Any CPU).
Some combination of lazy assembly loading/JIT in .NET means that the TFS assemblies aren't actually loaded until you hit your method call. By this time, your application is already committed to run as 64-bit, and so loading the 32-bit TFS assemblies fails - you can't mix bit-ness in one process. Permitting 32-bit apps in IIS isn't enough: you have to ensure that your application really does run as 32-bit by changing the compilation settings. In this case "Any CPU" is actually the culprit, because it's allowing your code to launch as 64-bit.
I say "some combination" because I'm not sure of the precise detail, but I have seen exactly the same issue in a console application, compiled as Any CPU and referencing the TFS DLLs. The solution was to compile the entrypoint assembly as 32-bit. Where this same code was consumed in a web service, we ended up shelling out to a separate process so that the web app wasn't reduced to 32-bit too.

Related

VS2017 Could not load file or assembly Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll or one of its dependencies

When trying to open an older solution in VS2017 there is an old Unit Test project that is giving me a problem when building.
I keep getting the following error when building this test project:
Could not load file or assembly 'file:///C:\Projects\MyProj\Test\DAL\UnitTestProj\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll' or one of its dependencies. The system cannot find the file specified.
I checked the project's references and it appears to be referencing Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll. Additionally there are no code errors. How could I ever figure out if it is one of its dependencies that it can't find?
I had a similar issue (with the additional message The "BuildShadowTask" task failed unexpectedly) with a project originally developed with VS2010, and got to spend the last few hours learning about yet another legacy facet of the build process.
There is a good chance that you are dealing with private accessor files (.accessor), which were deprecated in VS2012 (original source). This was foreshadowed in an announcement from the VS2010 team that they were no longer working on these features.
There is also a chance you're just dealing with erroneous refs to the wrong version of UnitTestFramework, but a NuGet restore should fix this. If not, see this GitHub thread for a possible fix (manually change the ref to the public folder), or move to the new MSTest.TestAdapter and MSTest.TestFramework packages (see MSDN support thread).
Solutions
A. Edit the unit test .csproj and change the item Include references from Shadow => None:
<Shadow Include="Test References\namespace.accessor" /> to
<None Include="Test References\namespace.accessor" />
B. Better yet, simply delete all the .accessor files from the unit test project's Test References folder.
Ideally, you would also rewrite your unit tests to remove references to private methods, either by re-architecting to separate concerns or by changing properties to internal and using "friend" with the InternalsVisibleToAttribute.
For those who need to continue supporting testing of private methods for some reason, the same post provides the following suggestions to the logical question "What is available for me then?":
For those who wish to continue testing internal APIs, you have three options:
Use the Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject class to assist in accessing internal and private APIs in your code. This is found in the Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll assembly.
Create a reflection framework that would be able to reflect off your code to access internal or private APIs.
If the code you are trying to access is internal, you may be able to access your APIs using the InternalsVisibleToAttribute so your test code can have access to the internal APIs.
However, there is not any good replacement for Code Generation for the new features added by the lanugage teams. You may create the TestMethod stubs and then remove the internal code. You only need to keep the stub itself.
Further reading / sources that helped me piece this together:
VS 2005 ASP.NET explanation of accessors
2008 blog article explaining how to work around this for build servers
MSDN forum thread with discussion on accessor purposes, implementations, and workarounds. Start about 1/3 down.
MSDN BaseShadow docs
MSDN PrivateObject class
Right click the project references folder. Add reference > Assemblies > extensions. Check Microsoft.VisualStudio.QualityTools.UnitTestFramework 10.1, and uncheck any older version.
This is related to Visual studio Enterprise 2015, add new load test was failing: and spiting as "Unable to find assembly 'Microsoft.VisualStudio.QualityTools.LoadTest, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Due to Assembly installed in public assemblies shows as version 10.0.0.0 which is missed in GAC,
GAC had only 10.1.0.0. Once GAC updated with 10.0.0.0 and restart VS 2015. should resolve the issue similar to this.
Some more detail for better reasoning, System Assembly path and project path
DLL path
......\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll
.CSProj reference version
I had a same issue while I was upgrading project to .Net4.8 in Visual studio 2022 earlier we were using Visual studio 2017.
Error:
The "BuildShadowTask" task could not be loaded from the assembly ***\Microsoft.VisualStudio.TestTools.BuildShadowsTask.dll. Could not load file or assembly 'file:///***Microsoft.VisualStudio.TestTools.BuildShadowsTask.dll' or one of its dependencies.
Solution : I removed ".accessor" files from project as that is being used for accessing private methods(most probably accessor is depricated). Then we used "PrivateObject" class for accessing private members in UnitTest.
Later we updated Unit Test case. Code references could be found from below articles.
Unit test private methods?
Unit Testing: Exposing Private Members
I had a similar issue (compile project in server Jenkins)
Solution:
Include VS.QualityTools.UnitTestFramework to reference project, whit Pakage Manager:
PM>NuGet\Install-Package VS.QualityTools.UnitTestFramework -Version 15.0.27323.2
https://www.nuget.org/packages/VS.QualityTools.UnitTestFramework
Try to fully uninstall Visual Studio 2017 (not repair). Then download the latest version and install it. Remember to check if MSBuild is added to installation files. Remember to delete folder inside Documents: Documents\Visual Studio 2017. In my case, this simple solution fixed all errors.

Native DLL dependencies with ASP.NET MVC Projects

EDIT: I found a way to get it to work locally, but on Azure I still get System.IO.FileNotFoundException on that assembly.
My question might seem like a duplicate to this question here. But it is slightly different, I have already tried that solution and it did not work. Here are the details.
I have an ASP.NET MVC App that has a Reference added to a third party CLR DLL. That third-party DLL requires a native DLL which it invokes. Now if I had control over where the Shadow Copying occurs and what is copied, I would be in paradise. The Shadow Copying misses copying that native DLL despite it's Build Action set as Content and Copy To Output Dir set as Copy Always.
So I searched internet and ran into this discussion on SO, which is same as what was mentioned earlier. I tried adding the code that sets the PATH Environment Variable inside Application_Init and Application_Start of Global.asax, I set the breakpoints in both the methods and to my surprise I get the ASP.NET Error Page before it even hits the breakpoint. This leads me to believe that the referenced assembly at the time of binding hits the native DLL and invokes it. What can I do? Can I delay the reference binding somehow?
EDIT: Yes we can, I opened the Referenced DLL's code which was written in Managed C++, I adjusted the linker setting to Delay Load the Native DLL and now my Application_Start executes first. Yayy! but that does not solve the same problem I am having on Azure
Here is the test solution with DLLs
Here is the source code for the Native DLL
Here is the source code for the Referenced Assembly that uses the Native DLL
To download the Native DLL distribution, Go to their distribution page, choose the windows archive with the bitness you desire (I am using 32-bit), and you will find amzi.dll inside APIs/bin directory.
Actual problem was the wrapper DLL not recognized on Azure server because of lack of support of earlier frameworks and toolsets, as well as Debug CRT.
I used XDT/Application_Start to set the PATH environment variable to include the location of my native DLL
I upgraded my Managed C++ Wrapper DLL to use Toolset 14.0 and .NET 4.6.2
Used Linker Setting of /DELAYLOAD on Managed C++ Wrapper DLL
After downloaded the DLLs and source code which you provided, I found that the native DLL depends on x64 platform. Firstly, we need to change the Platform property of our web app to x64 using Azure portal. If the platform button is disabled, you need to scale up your web app plan to Basic level plan or higher level.
In addition, the original path may end with “;”, so we need to check whether it contains “;” and append right content to it. Code below is for your reference.
string path = Environment.GetEnvironmentVariable("PATH");
Trace.TraceError(path);
string binDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Bin");
Trace.TraceError(binDir);
if (path.EndsWith(";"))
{
Environment.SetEnvironmentVariable("PATH", path + binDir);
}
else
{
Environment.SetEnvironmentVariable("PATH", path + ";" + binDir);
}
To test whether the path is set successfully, you could add a page to test it.
public ActionResult GetPath()
{
string path = Environment.GetEnvironmentVariable("PATH");
return Content(path);
}
After path is set, the native DLL can be load successfully on my side.
On my end I added a throw new ApplicationException("Test") at the beginning of Application_Start and instead of getting my test exception, I was getting the DLL load error.
It means the setting path code will not executed. To fix it, you could remove the native DLL reference from your web application. Now your application could work fine and set the path environment variable. Then you could add the native DLL reference back.
Another way to do it is that we could create a webjobs and set the path environment variable in webjobs and deploy this webjobs before deploying your web application.
I am using 32-bit distributions, my native dlls depends on x86/32-bit.
If you use 32-bit distributions and the platform targets of your CLR DLL and your web application are set to "x86 or Any CPU", you won't need to change platform to x64 in web app. Please change it back to x86.

UWP API in ASP.NET

I'd like to use a piece of Windows 10 specific UWP API (specifically, the Windows.Graphics.Printing3D stuff) in an ASP.NET code-behind DLL. Is there any way to do so?
While looking for a .NET-only resolution to this one, I've found a moderately clean way - a Win32/64 C++ DLL that would consume UWP API and present a COM- or P/Invoke-based interface to .NET.
Create a regular Win32 DLL. Build an interface for .NET to consume - exported functions or objects, depends. In my case, a single exported function will do. In the project's C/C++ settings, make the following changes:
Under General, set Consume Windows Runtime Extensions to Yes.
Under General, set Additional #using Directories to: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcpackages;C:\Program Files (x86)\Windows Kits\10\UnionMetadata (assuming Visual Studio 2015)
Under Code Generation, set Enable Minimal Rebuild to No (it's only Yes for Debug, not for Release).
Then instantiate and use UWP components in the DLL in the usual C++/CX manner, like you would in a Store app, via using namespace Windows::... and ref new.
In this approach, you lose bitness agnosticism; an unmanaged DLL can't be "Any CPU". You win some, you lose some. Also, the site will not run without the Visual C++ redistributable package on the system. On the other hand, it may run faster than a .NET app; less managed/native boundary crossings.
Inspiration: "Using C++/CX in Desktop apps" by Pavel Y.
Open the project file as XML, and paste the following line under the first <PropertyGroup>:
<TargetPlatformVersion>10.0</TargetPlatformVersion>
Once you do that, the Add reference dialog will include UWP libraries, and the file type options in the "Browse..." dialog there will include .winmd.
Load the project, do Add reference/Browse, locate C:\Program Files (x86)\Windows Kits\10\UnionMetadata\Windows.winmd, add that.
There are some helpful extension methods in the managed assembly System.Runtime.WindowsRuntime (e. g. IBuffer.AsStream()), but for some reason, it's not listed under Assemblies. To reference it, you'd need to edit the project file directly, and under the first <ItemGroup>, add the following:
<Reference Include="System.Runtime.WindowsRuntime" />
Unlike the guide states, you don't need to change the compilation target to x86 or x64; leave AnyCPU be.
For desktop .NET applications, this is sufficient. For ASP.NET, however, there's a catch. The way the ASP.NET runtime sets up its AppDomains not compatible with UWP. It's probably a bug deep down, but I've reported it, and a Microsoft rep said the whole thing was not a supported scenario to begin with.
Anyway, you have to change the LoaderOptimization policy of the AppDomain to SingleDomain. The quickest way to do so is via abusing a private method of AppDomain:
AppDomain ad = AppDomain.CurrentDomain;
MethodInfo mi = ad.GetType().GetMethod("SetupLoaderOptimization", BindingFlags.Instance | BindingFlags.NonPublic);
mi.Invoke(ad, new object[] { LoaderOptimization.SingleDomain });
A good place to do that would be in the app startup code.
A slightly less dangerous approach would involve creating a new AppDomain, which would inherit all setup properties from the current one but LoaderOptimization, which will be set to SingleDomain, and running the UWP dependent code in that domain. Like this:
AppDomain CreateUnsharingDomain()
{
AppDomain cad = AppDomain.CurrentDomain;
AppDomainSetup cads = cad.SetupInformation;
return AppDomain.CreateDomain("Dummy", cad.Evidence,
new AppDomainSetup
{
ApplicationName = cads.ApplicationName,
ApplicationBase = cads.ApplicationBase,
DynamicBase = cads.DynamicBase,
CachePath = cads.CachePath,
PrivateBinPath = cads.PrivateBinPath,
ShadowCopyDirectories = cads.ShadowCopyDirectories,
ShadowCopyFiles = cads.ShadowCopyFiles,
ApplicationTrust = cads.ApplicationTrust,
LoaderOptimization = LoaderOptimization.SingleDomain
});
//Not sure which other properties to copy...
}
CreateUnsharingDomain().DoCallBack(MyUWPDependentMethod);
Again, it would make sense to create the domain once and cache it for the app lifetime.
This approach might be faster than the one with the monkey-patched AppDomain. The MultiDomain optimization exists for a reason; if you leave most of the Web code in a MultiDomain world, the optimization will do its work as intended.
Inspiration: "Walkthrough: Using WinRT libraries from a Windows Desktop application" by David Moore.

Can instantiate component in the GAC from classic Asp

Going mad here.
I'm new to windows dev and I have registered my dll in the GAC.
I get a message saying "Assembly successfully added to the cache" and I can do a
Gacutil /l "its name" and see it there
But when I try to instatiate it in Classic asp like so:
Set TemperatureComponent = Server.CreateObject("comInteropTutorial")
I keep getting the error:
"Server object: 006~ASP 0177~Server.CreateObject Failed~800401f3"
which I believe means it can't find it?
I have also tried to do the same things for other components that were already in the Global cache like:
Set TemperatureComponent = Server.CreateObject("XamlBuildTask")
and the same thing happens.
Before adding the dll to the GAC, I did the following:
I compiled the dll in Visual studio 2010 and did the following:
Click on project
Application - sign the assembly
Build - register for Com interop
Signing - sign the assembly use a file that you have created using sn command (sn –k )
I'm truely stuck now, can someone recommend anything?
I'm on windows 7 here, dunno if that matters... 64 bit 32 bit etc?
I'd happily step through a process that helps me determine the cause of this problem if anyone can recommend one?
Looks like it is answered in another post: Accessing a .NET Assembly from classic ASP
...make sure your .Net assembly is set to
be COM Visible.
In Visual Studio, does the component show up in list of objects under the 'COM' table if you try to add it as a reference? Does the assembly depend on other assemblies or DLL's?
Just a guess here, sounds like either the regasm step is missing which adds the appropriate stuff to the registry, or in my case recently, IIS was running in 64bit, but the assembly was compiled for 32bit.

Error BC30002 - Type XXX is not defined

OK, this begins to drive me crazy. I have an asp.net webapp. Pretty straightforward, most of the code in the .aspx.vb, and a few classes in App_Code.
The problem, which has begun to occur only today (even though most of the code was already written), is that once in a while, I have this error message :
Error BC30002: Type ‘XXX’ is not defined
The error occurs about every time I modify the files in the App_Code folder. EDIT : OK, this happens also if I don't touch anything for a while then refresh the page. I'm still trying to figure out exactly how to trigger this error.
I just have to wait a little bit without touching anything, then refresh the page and it works, but it's very annoying.
So I searched a little bit, but nothing came up except imports missing. Any idea ?
I think I found the problem.
My code was like that :
Imports CMS
Sub Whatever()
Dim a as new Arbo.MyObject() ' Arbo is a namespace inside CMS
Dim b as new Util.MyOtherObject() ' Util is a namespace inside Util
End Sub
I'm not sure why I wrote it like that, but it turns out the fact I was calling classes without either calling their whole namespace or importing their whole namespace was triggering the error.
I rewrote it like this :
Imports CMS.Arbo
Imports CMS.Util
Sub Whatever()
Dim a as new MyObject()
Dim b as new MyOtherObject()
End Sub
And now it works...
This happened to me after I added a new project to an old solution. I lowered the Target framework to match that of the other 'older' projects and the error went away.
Sounds like a pre compile issue, particularly because you mention that you get the error and then wait and it disappears. ASP.NET may be still in the process of dynamically compiling your application or it has compiled the types into different assemblies.
With dynamic compilation, you are not guaranteed to have different codebehind files compiled into the same assembly. So the type you are referencing may not be able to be resolved within its precompiled assembly.
Try using the "#Reference" directive to indicate to the runtime that your page and the file that contains your type should be compiled into the same assembly.
# Reference - MSDN
Check for a compiler warning (Output window of Visual Studio) "warning : The following assembly has dependencies on a version of the .NET Framework that is higher than the target and might not load correctly during runtime causing a failure". This happens when one of your dlls is compiled with a newer version of dotnet. If your current project is set to use a lower version of dotnet, the dependency chain prevents the dll (with the higher dotnet ver) from loading. It gives a compile error in Visual Studio, but can still run in IIS.
Sounds like it happens every time the website spins up (the app gets recycled every time you touch app_code and probably you have IIS configured to shut down the website after X minutes of inactivity).
I bet it has something to do with the asp.net worker process not having the correct access rights on the server. So its trying to load an assembly and is being denied.
Check this link and Table 19.3 for a list of all the folders the worker process account must have access to in order to function. And don't forget to give it rights to all files and folders in your virtual directory!
Replace your vbproj and vbproj.user file from your backup before if the references are equal

Resources