Assembly.UnsafeLoadFrom causes web app crash - asp.net

I am trying to load a DLL from internet, more specifically it is Azure storage (Blob), so I used "Assembly.UnsafeLoadFrom" like this:
Assembly.UnsafeLoadFrom(#"https://accountname.blob.core.windows.net/test/calculator.dll");
But becuaset this specific call, my web app (published) returns:
"The specified CGI application encountered an error and the server
terminated the process."
The weird part is if I am using my local build, it is fine. there is no crash and the return result is correct.
I am using Visual Studio 2015 and .net 5.
Please let me know how to resolve this issue or how to debug it.
Thanks

For a simple way, you could achieve your purpose by the following code:
calculator.dll
public class Calculator
{
public string HelloWorld(string userName)
{
return string.Format("Hello world, {0}!", userName);
}
}
HomeController.cs
public async Task<ActionResult> Index()
{
string url = "https://brucechen.blob.core.windows.net/dll/calculator.dll";
HttpClient client = new HttpClient();
var bytes = await client.GetByteArrayAsync(url);
//load assembly from bytes
Assembly assembly = Assembly.Load(bytes);
var calc = assembly.CreateInstance("calculator.Calculator");
//invoke the method and get result
var result = calc.GetType().InvokeMember("HelloWorld", BindingFlags.InvokeMethod, null, calc, new[] { "Bruce" });
ViewData["result"] = result;
return View();
}
Result

Related

Consuming asp.net core web api in asp.net core mvc web app

I'm trying to consume my asp.net web api in my asp.net core mvc web app which are on the same solution. I configured the solution for multi-project start and they start both.
next I tried to consume the API in the Web part but I'm getting the following error.
InvalidOperationException: A suitable constructor for type 'ProjectName.Web.Services.Interfaces.IAdminService' could not be located. Ensure the type is concrete and all parameters of a public constructor are either registered as services or passed as arguments. Also ensure no extraneous arguments are provided.
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.FindApplicableConstructor(Type instanceType, Type[] argumentTypes, out ConstructorInfo matchingConstructor, out Nullable[] matchingParameterMap)
Here is the complete Stack trace
The Projects are structure like this
SolutionName:
Name.API
Name.Web
each with its own respective structure
This is my Helper Class
public static class HttpClientExtensions
{
public static async Task<T> ReadContentAsync<T>(this HttpResponseMessage response)
{
//if (response.IsSuccessStatusCode == false) return StatusCodes = 300;
//throw new ApplicationException($"Something went wrong calling the API: {response.ReasonPhrase}");
var dataAsString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var result = JsonSerializer.Deserialize<T>(
dataAsString, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
return result;
}
}
The IAdmin Inter Face
Task<IEnumerable<Admins>> GetAllAdmins();
The AdminService(Implementation)
private readonly HttpClient _client;
public const string BasePath = "api/Admins";
public AdminService(HttpClient client)
{
_client = client; // ?? throw new ArgumentNullException(nameof(client));
}
public async Task<IEnumerable<Admins>> GetAllAdmins()
{
var response = await _client.GetAsync(BasePath);
return await response.ReadContentAsync<List<Admins>>();
}
Admins Controller
private readonly IAdminService _adminService;
public AdminController(IAdminService adminService)
{
_adminService = adminService;
}
public async Task<IActionResult> Index()
{
var adminsList = await _adminService.GetAllAdmins();
if(adminsList == null)
{
return new JsonResult("There are now Admins");
}
return View(adminsList);
}
Program.cs
builder.Services.AddControllersWithViews();
builder.Services.AddHttpClient<IAdminService, IAdminService>(c =>
c.BaseAddress = new Uri("https://localhost:<port-Num>/"));
var app = builder.Build();
What Could I be doing wrong???
I'm using .NET 6 adn both Projects are in the same solution
NB My end points are working fine, I test them using Postman.
It is failing because DI cannot instantiate your AdminService with parameterized constructor. This is possibly a duplicate of Combining DI with constructor parameters? .
Essentially, you should avoid parameterized constructor injection where possible. Either control it through configuration or have the configuration loaded through common infrastructure such as host configuration.
According to your codes, I found you put two interface inside the AddHttpClient method which caused the issue.
I suggest you could modify it like this and then it will work well.
builder.Services.AddHttpClient<IAdminService, AdminService>(c =>
c.BaseAddress = new Uri("https://localhost:3333/"));

Cognitive Face API returning No result from Web Application

I am using the Microsoft Cognitive Face API for implementing the Face Detection to Authenticate the person and login to the application.
For that, I am creating a PersonGroup and add the Person and then Face of Person. Train Person group and so on.
I want to implement it in the MVC Web Application. I have written the same code in MVC Web Application. But the API is not returning anything and just hanged at the Http request call.
So Do we need to get some different API Key for a Web application or Do we need to make any changes in Web.Config file to make a successful call?
I have tried the same code in the Console Application and WPF Application. There everything works perfectly fine.
public class HttpClientHelper
{
HttpClient httpClient = new HttpClient();
private const string subscriptionKey = "XXXXXXXXXXXXXXXXXXXXXXXXXX";
private const string faceEndpoint = "https://southeastasia.api.cognitive.microsoft.com/face/v1.0/";
public HttpClientHelper()
{
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
httpClient.BaseAddress = new Uri(faceEndpoint);
}
public async Task<T> GetAsync<T>(string url)
{
var response = await httpClient.GetAsync(url);
string contentString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(contentString);
}
}
public static async Task CreatePersonGroup(UserGroup userGroup)
{
bool isGroupExists = false;
PersonGroup personGroup;
try
{
HttpClientHelper httpClientHelper = new HttpClientHelper();
var response = httpClientHelper.GetAsync<PersonGroup>(string.Format("persongroups/{0}", userGroup.UserGroupId)).Result;
isGroupExists = true;
}
catch (APIErrorException ex)
{
if (ex.Body.Error.Code == "PersonGroupNotFound")
isGroupExists = false;
}
if (isGroupExists == false)
{
await faceClient.PersonGroup.CreateAsync(userGroup.UserGroupId, userGroup.Name);
}
}
I expect the same code must be working fine in Web Application also. As there is not a big logic in it. Just a simple API call.
private const string faceEndpoint =
"https://southeastasia.api.cognitive.microsoft.com/";
hopefully, it should work

Using Web.Api to asynchronously log errors for asp.net mvc

I have a legacy logging DLL that logs errors into a database. Instead of consuming the DLL within each application in our environment, we would like to make web calls to log errors.
I have built up a web.api app that will log errors into a database. When tested with POSTMAN it works as advertised.
I have added a class within a demo MVC app and wired up one of my constructors to execute a log command, but the call not only does not make it to my web.api, but fiddler does not show a call even being made.
Any input on making this actually run would be greatly appreciated.
Here's my code:
Logging Utility Called within Web.API
public class Utilities
{
public void LogException(string exceptionMessage, string stackTrace, string appCode, string runMode, int entityId, int itmsUserID, string updateBy, string path, string method)
{
ErrorLog.Entry _error = new ErrorLog.Entry();
_error.ErrorMessage = exceptionMessage;
_error.StackTrace = stackTrace;
_error.AppCode = appCode;
_error.Path = path;
_error.Method = method;
_error.UpdateBy = updateBy;
_error.RunMode = runMode;
_error.EntityID = entityId;
//_error.Server = server; server will have to be changed to accept a setter
_error.ITMSUserID = CommonFunctions.Get_ITMSUserID(updateBy);
_error.Save();
}
}
Web.API
// POST: api/ErrorLog
public void Post([FromBody]ErrorLogEntryDTO item)
{
var utils = new Utilities();
utils.LogException(item.ErrorMessage, item.StackTrace, item.AppCode, item.RunMode, item.EntityID, item.ITMSUserID, item.UpdateBy, item.Path, item.Method);
}
MVC Controller Code
// GET: BillingRules/Create
public virtual ActionResult CauseHandledError()
{
try
{
throw new Exception("Handled exception test");
}
catch (Exception ex)
{
var utils = new Utilities();
utils.LogException(ex, "system", MVC.BillingRules.Name, MVC.BillingRules.ActionNames.CauseHandledError);
}
return RedirectToAction(MVC.BillingRules.ActionNames.Index, MVC.BillingRules.Name);
}
Utilities Code within MVC App
public void LogException(Exception exception, string updateBy, string path, string method)
{
try
{
var itmsUserID = CommonFunctions.Get_ITMSUserID(updateBy);
var errorDTO = new ErrorLogEntryDTO();
errorDTO.ITMSUserID = itmsUserID;
errorDTO.AppCode = _appCode.Value;
errorDTO.ErrorMessage = exception.Message;
errorDTO.StackTrace = exception.StackTrace;
errorDTO.Path = path;
errorDTO.Method = method;
errorDTO.UpdateBy = updateBy;
var client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:52316");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var result = client.PostAsJsonAsync("api/ErrorLog", errorDTO).Result; //ContinueWith(readTask => client.Dispose()); //
}
catch (Exception ex)
{
var myError = ex;
throw;
}
}
I'm pretty sure calling .Result in this instance does not immediately invoke the PostAsJsonAsync method. Because you're not doing anything with the Result, it never actually executes. Since it doesn't appear you care about the response, you should be able to use:
client.PostAsJsonAsync("api/ErrorLog", errorDTO).Wait();
I think .Result invokes the PostAsJsonAsync call. You are waiting for the respsonse, so the call must be finished after this line. Regardless if you use the Result or not.
You can remove the [FromBody] attribute, because the complex type is per default read from the body.
And I can't reproduce your issue. I've created a new Web API project and a new console project. In the Web API I've changed the post of the valuescontroller to yours.
In the console project I'm yousing your LogException() method from the MVC app.
It hits my web api app.
Are both in the same host or in different hosts?
Edit:
To make your logging async you can use fire-and-forget with Task.Run() but it depends on the application you have. In ASP.Net Task.Run() is an anti-pattern according to Task.Run Etiquette Examples: Don't Use Task.Run in the Implementation.

Uploading a file from .NET application to a Web API POST endpoint

I'd like to use Web API to build some endpoints for applications to consume. The first job I'd like it to do is allow the client to upload a file to the server.
The client will run a .NET app of some kind, maybe a console app or maybe something else. It won't be a webpage using a form element or file input.
I think the Web API would look something like this:
public class FileController : ApiController
{
public bool Post(File newFile)
{
return true;
}
}
Using this as a model class:
public class File
{
public string name { get; set; }
public Stream uploadStream { get; set; }
}
I'm sure that's horribly wrong but it's my first Web API.
I'm trying to test this in a console application:
namespace TestFileUpload
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting the test...");
using (FileStream readstream = new FileStream(#"C:\\Test\Test2.txt", FileMode.Open, FileAccess.Read))
{
WebAPI.Classes.File newFile = new WebAPI.Classes.File()
{
name = "Test.txt",
uploadStream = readstream
};
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:50326");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response;
response = client.PostAsJsonAsync("http://localhost:50326/api/file", newFile).Result;
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
};
Console.ReadLine();
}
}
}
Now I'm getting a timeout error when I try to get the response:
"Error getting value from 'ReadTimeout' on 'System.IO.FileStream'."
Help?
There are many ways for a client to consume a Web API service, but the most straight forward would be to use the web api client library. Perhaps you should consider building a simple get method that returns an object before jumping into file uploads.
Web API from .NET Client
You can not add a service reference as Web API does not expose a wsdl.

LiveAuthClient broken?

It seems very much that the current version of LiveAuthClient is either broken or something in my setup/configuration is. I obtained LiveSDK version 5.4.3499.620 via Package Manager Console.
I'm developing an ASP.NET application and the problem is that the LiveAuthClient-class seems to not have the necessary members/events for authentication so it's basically unusable.
Notice that InitializeAsync is misspelled aswell.
What's wrong?
UPDATE:
I obtained another version of LiveSDK which is for ASP.NET applications but now I get the exception "Could not find key with id 1" everytime I try either InitializeSessionAsync or ExchangeAuthCodeAsync.
https://github.com/liveservices/LiveSDK-for-Windows/issues/3
I don't think this is a proper way to fix the issue but I don't have other options at the moment.
I'm a little late to the party, but since I stumbled across this trying to solve what I assume is the same problem (authenticating users with Live), I'll describe how I got it working.
First, the correct NuGet package for an ASP.NET project is LiveSDKServer.
Next, getting user info is a multi-step process:
Send the user to Live so they can authorize your app to access their data (the extent of which is determined by the "scopes" you specify)
Live redirects back to you with an access code
You then request user information using the access code
This is described fairly well in the Live SDK documentation, but I'll include my very simple working example below to put it all together. Managing tokens, user data, and exceptions is up to you.
public class HomeController : Controller
{
private const string ClientId = "your client id";
private const string ClientSecret = "your client secret";
private const string RedirectUrl = "http://yourdomain.com/home/livecallback";
[HttpGet]
public ActionResult Index()
{
// This is just a page with a link to home/signin
return View();
}
[HttpGet]
public RedirectResult SignIn()
{
// Send the user over to Live so they can authorize your application.
// Specify whatever scopes you need.
var authClient = new LiveAuthClient(ClientId, ClientSecret, RedirectUrl);
var scopes = new [] { "wl.signin", "wl.basic" };
var loginUrl = authClient.GetLoginUrl(scopes);
return Redirect(loginUrl);
}
[HttpGet]
public async Task<ActionResult> LiveCallback(string code)
{
// Get an access token using the authorization code
var authClient = new LiveAuthClient(ClientId, ClientSecret, RedirectUrl);
var exchangeResult = await authClient.ExchangeAuthCodeAsync(HttpContext);
if (exchangeResult.Status == LiveConnectSessionStatus.Connected)
{
var connectClient = new LiveConnectClient(authClient.Session);
var connectResult = await connectClient.GetAsync("me");
if (connectResult != null)
{
dynamic me = connectResult.Result;
ViewBag.Username = me.name; // <-- Access user info
}
}
return View("Index");
}
}

Resources