How to step inside/debugging the code source of web.api 2 and System.Web dll - asp.net

I wanted to step inside/debugging the web-api 2 (version 5.2.3) code source to understand it.
I've created a simple web api application, and in the WebApi.config, i've setted a break point at this line :
config.Routes.MapHttpRoute(
name: "ExcludedRoute",
routeTemplate: "api/{controller}/{action}",
defaults: new { id = RouteParameter.Optional },
constraints: new { Controller = "healthcheck", action = "check" }
);
I could step inside the MapHttpRoute method and the other classes, but the debugger couldn't step inside the Route class from the System.Web dll, below the image:
I tried to use this symbol file locations:
I've also used the dotpeek tool for generating the pdb files from the bin folder, by setting to true the "copy local" feature of the referenced assemblies, but with no success. The path of system.web dll is
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.5\System.Web.dll
I'm wondering Why the debugger couldn't step inside the Route class wich belongs to the system.Web dll, its version is 4.0 and the version of web.api is the 5.2.3.
In my searching, i've downloaded the code source of the asp.net and i found that the project System.Web.Http.WebHost which contains the HttpWebRoute class.
Any idea?
Thanks!

Assembly System.Web.pdb was in the .NET Framework source code. You need to configure Visual Studio for debugging .NET framework in the Tools -> Options -> Debugging -> General menu.
Reference:
How do I debug .NET 4.6 framework source code in Visual Studio 2017?

Related

aspnet core appsettings.json loading

I have ASP.NET Core (2.1) project that has appsettings.json. I use WebHost.CreateDefaultBuilder(). The appsettings.json file has following configuration in File Properties:
Build Action: Content
Copy to Output Directory: Do not copy
After build the appsettings.json ends up in bin\Debug\netcoreapp2.1\MyProj.runtimeconfig.json.
The ASP.NET Core runtime loads it fine.
I created WebJobs (for .Net Core 2.1) and wanted to do the same - set Build Action to Content and let it loaded. In the Main() of Program.cs I have code like
var builder = new HostBuilder()
...
.ConfigureAppConfiguration(b =>
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
b.SetBasePath(Directory.GetCurrentDirectory());
b.AddJsonFile("appsettings.json", false, true);
b.AddJsonFile($"appsettings.{environment}.json", true, true);
b.AddEnvironmentVariables();
// Adding command line as a configuration source
if (args != null)
{
b.AddCommandLine(args);
}
}
But the runtime tries to load appsettings.json (instead of MyWebJobProj.runtimeconfig.json). So I had to set Build Action to None and Copy to Output Directory to Always.
However I would prefer the same approach like in ASP.NET Core - it handles somehow the file name transformation. Although in WebHost.CreateDefaultBuilder() is basically the same code like I have in my WebJob. What does the magic file name transformation in the configuration and why it works only in one type of project?
The file [ProjName].runtimeconfig.json has a completely different meaning than appsettings.json. Ensure that appsettings.json was copied to output (set 'Copy to output' to 'always' or 'newer').

Entry point not found in .NET Core 2.0 DLL

I couldn't find anything that explains this -- for some reason my .NET Core 2.0 ASP.NET application does not run as a DLL via:
dotnet MyProject.Web.dll
And instead I get the exception:
Unhandled Exception: System.MissingMethodException: Entry point not found in assembly 'MyProject.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
namespace MyProject.Web
{
public class Program
{
public static void Main(string[] args)
{
LoadDependencies();
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
private static void LoadDependencies()
{
DependencyLocator.Instance.DefineIfUndefined<IDataProvider, DataProvider>();
}
}
}
It runs fine as a standalone executable (when targeting a "Console Application" in the project's config), but now that I'm trying to deploy to a server that needs it to run via the dotnet command (as a DLL, i.e. "dotnet .\MyProject.Web.dll"), it seems to be having issues. I get the above exception on both my server and my local development box.
I'm kind of blown away that it cannot locate the Main method -- it's declared as static and in Program.cs. Am I missing something?
(EDIT: To clarify, the DLL I'm trying to run against the "dotnet" command is from the target compiling as a "Console Library," since my server is explicitly asking for a DLL, since they will not run executables).
OK, so this is annoying and will hopefully help someone else out.
My host wants to specifically run DLL's thru .NET Core ONLY. They do not allow for executables to be run.
Because DLL's are frequently built as "Class Library" output types on the project, I assumed that this was the workflow necessary to build it. However, I found out that whenever you build your project as a "Console Application," it builds a DLL in addition to an EXE. So, in the above example, MyProject.Web.exe and MyProject.Web.dll are both built when the output type is "Console Application."
MyProject.Web.dll that comes from "Console Application" is different than MyProject.Web.Dll that comes from "Class Library." The one that comes from "Class Library" will NOT have an entry point that can be discovered on it, which will lead to the problem above.
So, if you're getting this error, look for the DLL that ships with your EXE of the same name -- that's the actual DLL you'll want to run in your dotnet console (i.e. dotnet MyProject.Web.dll)

Using T4 with .NET Core 2.0 and referencing a package from a template

I tried using T4 in a .NET Core 2.0 app project but it seems that T4 doesn't recognize included namespaces. For example, after installing Microsoft.AspNetCore.All package and having the following piece of code:
<## import namespace="Microsoft.Extensions.Configuration" #>
<#+
public class ConfigurationHelper
{
public string ReadConfig(){
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("Configuration\\CodeGenerationConfig.json");
IConfigurationRoot Configuration = builder.Build();
return Configuration["ConnectionString:Server"];
}
}
#>
I got the error:
The type or namespace name 'IConfigurationRoot' could not be found
(are you missing a using directive or an assembly reference?)
Even I tried using assembly directive:
<## assembly name="C:\Program
Files\dotnet\store\x64\netcoreapp2.0\microsoft.extensions.configuration\2.0.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll"
>
But the following error occurred:
System.IO.FileLoadException: Could not load file or assembly
'file:///C:\Program
Files\dotnet\store\x64\netcoreapp2.0\microsoft.extensions.configuration\2.0.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll'
or one of its dependencies. Strong name signature could not be
verified. The assembly may have been tampered with, or it was delay
signed but not fully signed with the correct private key. (Exception
from HRESULT: 0x80131045)
So the question is how can I reference a .NET Core package from within a T4 template?
P.S: I tried Scripty, but it doesn't support .NET Core yet.
Update:
The Visual Studio 2017 and Xamarin Studio now supports to process *.tt files in desing time
but https://github.com/ZeekoZhu/TextTemplatingCore may still be useful if you want to process T4 templates in a dotnet core(netstandard2.0)
project outside IDE (eg. in Linux or macOS with Visual Studio Code)

InvalidOperationException: Could not find 'UserSecretsIdAttribute' on assembly

After deploying ASP.NET Core app to azure and opening the site, I get the following error:
InvalidOperationException: Could not find 'UserSecretsIdAttribute' on
assembly '******, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null'.
The exception details also include that the error happens at Startup.cs on this line of code:
builder.AddUserSecrets();
Thank you
There was an update to the user secrets module just recently. Version 1.0.1 and up now requires you specify an assembly-level attribute for the id of the user secrets, or as a fallback, the way it was previously in project.json.
Here is the announcement on GitHub: https://github.com/aspnet/Announcements/issues/209
You can define the secrets id in the .csproj like this:
<PropertyGroup>
<UserSecretsId>aspnet-TestApp-ce345b64-19cf-4972-b34f-d16f2e7976ed</UserSecretsId>
</PropertyGroup>
This generates the following assembly-level attribute. Alternatively, instead of adding it in the .csproj file, you can of course add it yourself e.g. to Startup.cs:
[assembly: UserSecretsId("aspnet-TestApp-ce345b64-19cf-4972-b34f-d16f2e7976ed")]
Also, you should use:
builder.AddUserSecrets<Startup>();
It will search for that attribute in the assembly of the given type, in this case I used the Startup class.
Note: this will be deprecated in 2.0: (1.0.2 and 1.1.1 have marked it obsolete)
builder.AddUserSecrets();
I checked the source code for the user secrets configuration, and calling AddUserSecrets() without the type does this:
var attribute = entryAssembly.GetCustomAttribute<UserSecretsIdAttribute>();
if (attribute != null)
{
return AddUserSecrets(configuration, attribute.UserSecretsId);
}
// try fallback to project.json for legacy support
try
{
var fileProvider = configuration.GetFileProvider();
return AddSecretsFile(configuration, PathHelper.GetSecretsPath(fileProvider));
}
catch
{ }
// Show the error about missing UserSecretIdAttribute instead an error about missing
// project.json as PJ is going away.
throw MissingAttributeException(entryAssembly);
It's trying to find the UserSecretsId attribute on your assembly, and failing that, checking if it could find it in project.json. Then (as commented) returns an error about the missing attribute as they wouldn't want to complain about project.json anymore as it is being deprecated.
I want to add to this answer, for those in my situation.
I am writing a .NET Core console app, trying to use the secrets manager (not sure it's meant for console apps). The only way I was able to rid myself of the error was using the assembly level attribute on the assembly where I was using the secrets manager.
As I said, I am not sure if the secrets manager is meant for console apps. So maybe there is an issue with .xproj files vs. .csproj files.
My .NET Core 3.1 Worker Service required additional setup (more than a Web project).
In Program.cs in the CreateHostBuilder method I needed this:
.ConfigureAppConfiguration((ctx, builder) =>
{
// enable secrets in development
if (ctx.HostingEnvironment.IsDevelopment())
{
builder.AddUserSecrets<Worker>();
}
})
But (unlike my Web project) I explicitly needed to add this nuget package:
install-package Microsoft.Extensions.Configuration.UserSecrets
After that I could access secrets.

ASP.net app crashes - Could not load file or assembly 'Microsoft.Threading.Tasks.Extensions.Desktop'

I want to build a Google BigQuery C# ASP.net application using OAuth2 and the .Net 4.5 framework. I ran these NuGet installs
Install-Package Google.Apis.Bigquery.v2 -Pre
Install-Package Google.Apis.Authentication.OAuth2 -Version 1.2.4696.27634
Install-Package Google.Apis -Pre
Install-Package Google.Apis.Auth -Pre
and I placed the relevant "usings" in code-behind file "default.aspx.cs":
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Bigquery.v2;
using Google.Apis.Bigquery.v2.Data;
namespace BigQueryDemoApp
{
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
UserCredential credential;
FileStream stream;
using (stream = new FileStream(
Server.MapPath("~/client_secrets.json"),
FileMode.Open, FileAccess.Read)
)
{
GoogleWebAuthorizationBroker.Folder =
"Tasks.Auth.Store";
credential = GoogleWebAuthorizationBroker.
AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { BigqueryService.Scope.Bigquery },
"user", CancellationToken.None).Result;
}
// Initialize the service.
var Service = new BigqueryService(
new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "BigQueryDemo"
}
);
}
}
}
I set this specific page as the project start page. I picked "Installed application" when I built the Client ID file at the Google console
APIS & auth -> Credentials -> CREATE NEW CLIENT ID
and I made sure I added this file (client_secrets.json) with the solution explorer in VS2013. In the code-behind, I made sure that I correctly mapped to the client_secrets file with Server.MapPath. For the credential machinery, I used this code
<https://code.google.com/p/google-api-dotnet-client/wiki/OAuth2>
as the starting point. When I run the app, it returns a browser error page that starts with
Could not load file or assembly 'Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.16.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
and crashes at the "credential =" line. I tried to add in some images of the actual ASP.net crashed browser page showing the Assembly Load Trace / Stack Trace / etc. but it looks like I don't have the account rights for this. When I set a breakpoint at the "credential =" line and then run the app through
DEBUG -> Start Debugging
in VS2013, the page stops at the "credential =" line and a file picker opens, looking for file
"GoogleClientSecrets.cs"
from directory
"c:\code\google.com\google-api-dotnet-client\default\Tools\Google.Apis.Release\bin\Debug\output\default\Src\GoogleApis.Auth\OAuth2\GoogleClientSecrets.cs"
which is nowhere on the drive. Using the Assembly Load Trace in the generated ASP.net error page, I tried digging around through the suggested configuration files but nothing worked. More generally, I tried looking for this issue in StackOverflow and while I did find some mention of it, none of that material helped.
Because the error is based on the fact that the latest version of Microsoft.Bcl.Async doesn't work in .NET 4.5, you can try to do the following:
Open your Package Manager Console, and run the following commands:
1) Uninstall-Package Microsoft.Bcl.Async -Force
2) Install-Package Microsoft.Bcl.Async -Version 1.0.16
It works in a sample I'm currently writing. Please let me know if it works for you.
UPDATE (March 21st):
You can update the package (new version 1.0.166-beta is available - https://www.nuget.org/packages/Microsoft.Bcl.Async/1.0.166-beta).
I tested it on VS2013 with .NET 4.5 framework and it works.
They released a new version of -Package Microsoft.Bcl.Async.
If somebody has this issue, please install the "latest" version instead of 1.0.16.
I hope it works for you.
I already encountered this error before. It looks like the Bcl.Async package contains a reference to Microsoft.Threading.Tasks.Extensions.Desktop when you run a .NET 4.0 applications but somehow it is missing in .NET 4.5 application.
My advice for you (until I'll figure our with the owner of Microsoft.Bcl.Async why it happens) is to copy Microsoft.Threading.Tasks.Extensions.Desktop from packages\Microsoft.Bcl.Async.1.0.165\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll to your BIN folder. It should solve this issue.
UPDATE (March 17th):
Consider adding the following Post-build event to your project:
copy /Y "$(SolutionDir)packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll" "$(TargetDir)Microsoft.Threading.Tasks.Extensions.Desktop.dll"
Unfortunately, there isn't a solution for this problem yet from the owners of the Bcl.Async package.
This approach did not fix the issue - I got the same runtime error. But after a rebuild, I noticed that the VS2013 compiler showed this warning, which I formatted a little for the SO editor
C:\Program Files (x86)\MSBuild\12.0\bin\Microsoft.Common.CurrentVersion.targets(1635,5): warning
MSB3247: Found conflicts between different versions of the same dependent assembly. In Visual
Studio, double-click this warning (or select it and press Enter) to fix the conflicts;
otherwise, add the following binding redirects to the "runtime" node in the application
configuration file:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Threading.Tasks.Extensions.Desktop" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-1.0.165.0" newVersion="1.0.165.0" />
</dependentAssembly>
</assemblyBinding>
so I dropped the suggested block in the app web.config file. Then the app decided to work. I have no idea why it works now, but I get the impression that the XML block and / or the reference fix you mentioned somehow touched the Microsoft.Threading.Tasks.Extensions.Desktop DLL, or some low-level machinery inside .Net, or both. Or neither, for all I know. Anyway, thanks for your help. I only wish I had a better understanding of the internal machinery.

Resources