Why Request is null in my controller? - c#

I call a a methode by HttpPost in my ServiceController from my View http://localhost/Case/Form
My serviceController class:
using System.Web;
using System.Web.Mvc;
[...]
namespace ApnNephro.WebUI.Controllers
{
public class ServicesController : Controller
{
public string GetDomain()
{
string url = "";
try
{
string _url = Request.Url.AbsolutePath;
int _si = (_url.IndexOf("//"));
int _fi = (_url.Substring(_si + 2)).IndexOf("/"); // first /
url = _url.Substring(0, _fi + _si + 2);
return url.ToString();
}
catch (InvalidOperationException ioe)
{
throw new Exception(ioe.Message + " / " + ioe.StackTrace);
}
catch (Exception e)
{
throw new Exception(e.Message + " / " + e.StackTrace);
}
return url.ToString();
}
[...]
And i call him in my MailHelper.cs :
private static string domain = new ServicesController().GetDomain();
But an exception occure because Request is null...
So, my Question is, why Request is null ?
Is it assigned only in the current view controller, so here in my CaseController only ?

You are creating a new controller, that is not associated with a request.
Instead of putting the get domain in a controller and then creating a new one,
You can just access the current request via the HttpContext.Current.Request.
This is also available in a static method.

Related

How to use C# HTTPClient with Windows Credentials

I wrote a console app that will read a text file of links and test them using the HttpClient class to check if the links exist. It works wonderfully at home when tested against common links such as google.com.
When I run the app at under my work intranet, though, I get "Forbidden" errors when it checks links on our company Sharepoint and "Unauthorized" errors when it checks links on the Azure Website. My hope was that running it under my authorized Windows desktop PC would be all I needed for it to work, but nope.
Any hints one how to pass my Network credentials when I access the links with HttpClient?
EDIT: Added code to handle passed console argument (string of authentication cookies)
using System;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
namespace linkbot
{
class Program
{
private static async Task ProcessRepositories(string the_url, string the_cookies)
{ int the_index=the_url.IndexOf("/",9);
string base_string=the_url;
string the_rest="/";
if (the_index>=0)
{
base_string=the_url.Substring(0,the_index);
the_rest=the_url.Substring(the_index);
}
try {
var baseAddress = new Uri(base_string);
using (var handler = new HttpClientHandler { UseCookies = false })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var message = new HttpRequestMessage(HttpMethod.Get, the_rest);
message.Headers.Add("Cookie", the_cookies);
var result = await client.SendAsync(message);
result.EnsureSuccessStatusCode();
}
Write("\n" + the_url + " - WORKED!");
}
catch(Exception e )
{
Write("\nFailed: " + the_url + "||||||" +e.ToString() );
//throw e;
}
}
static async Task Main(string[] args)
{
if (args.Length<2){
Console.Write("\n###################\nLinkChecker by Sean J. Miller 2022\n\nusage:\n linkchecker.exe <linkfile> <cookies>\nwhere <linkfile> contains a text file of fully specified links (URLs) with one link per line. Example, https://www.google.com\n\nAn output file is generated titled brokenlinks.txt in the same directory where LinkChecker was launched. <cookies> should be a string such as \"cookie1=value1;cookie2=value2;cookie3=value3;\"\n###################\n\n\n");
return;
}
System.IO.File.Delete("brokenlinks.txt");
System.IO.File.WriteAllText("brokenlinks.txt", "Last Check Started " + (DateTime.Now).ToString());
int counter=0;
int total_lines=TotalLines(#args[0]);
Console.Write("Started " + (DateTime.Now).ToString() + "\n");
foreach (string line in System.IO.File.ReadLines(#args[0]))
{
Console.Write("Processing Link " + (++counter) + "/" + total_lines + "\n");
await ProcessRepositories(line, args[1]);
}
Console.Write("Finished " + (DateTime.Now).ToString() + "\n");
Write("\n");
}
static void Write(string the_text)
{
//Console.Write(the_text);
try
{
System.IO.File.AppendAllText("brokenlinks.txt", the_text);
}
catch (Exception ex)
{
throw ex;
}
}
static int TotalLines(string filePath)
{
using (StreamReader r = new StreamReader(filePath))
{
int i = 0;
while (r.ReadLine() != null) { i++; }
return i;
}
}
}
}
You want to set UseDefaultCredentials to true to use the current logged-on user credentials in your request. You can do that by instantiating your HttpClient like so:
private static readonly HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });

ASP.NET MVC How to debug a published folder

Good day Someone.
I am new to asp.net mvc.
I created a simple web application using asp.net mvc.
The application is used to upload image from to a folder. The application works well in visual studio, but once i publish and put on iis it does not upload the image.
I am thinking if there is way to debug the published version so that i can get where the issued is ?
Kindly help on how i can debug the published version and how to solve the problem .
Below is where it is catching the error
string path = System.IO.Path.Combine(targetLocation, file.FileName);
I Would suggest doing the debugging for ASP.NET MVC Application to follow the below points.
Server-side - You should use do exception filter to write any issues to text files and track it
Front - End - the developer tool in the browser level for javascript related things.
DataBase Side - You can use the SQL profiler to use catch the server-side debugging.
add try catch block in your codes
and in the catch code log the exception error message into a file in server to see what is the exact error as following:
add this model to your solution under "Models" folder or anywhere
public class ExceptionLogger
{
private string sLogFormat;
public void ErrorLog(string sErrMsg)
{
try
{
string LogDirectory = "C:\LogFiles\";
CheckCreateLogDirectory(LogDirectory);
LogDirectory = (LogDirectory + "Log_" + DateTime.Now.ToString("dd_MM_yyyy", new CultureInfo("en-us")) + ".txt");
sLogFormat = DateTime.Now.ToString("dd/MM/yyyy", new CultureInfo("en-us")) + " " + DateTime.Now.ToString("HH:mm:ss", new CultureInfo("en-us")) + " ==> ";
StreamWriter sw = new StreamWriter(LogDirectory, true);
sw.WriteLine(sLogFormat + sErrMsg);
sw.Flush();
sw.Close();
}
catch (Exception e) {
}
}
private bool CheckCreateLogDirectory(string LogPath)
{
bool loggingDirectoryExists = false;
DirectoryInfo oDirectoryInfo = new DirectoryInfo(LogPath);
if (oDirectoryInfo.Exists)
{
loggingDirectoryExists = true;
}
else
{
try
{
Directory.CreateDirectory(LogPath);
loggingDirectoryExists = true;
}
catch
{
throw new Exception();
// Logging failure
}
}
return loggingDirectoryExists;
}
}
Then in your controller or repository where errors may happen do the following:
a- add this code in top:
ExceptionLogger Err = new ExceptionLogger();
//you need to write "using" in top to refactor the import error
// something like this: using YourProjectName.Models;
b- in your code blocks add try catch block
try{
//your code
}catch(Exception ex){
Err.ErrorLog(ex.Message + " --- , ---- " + ex.InnerException);
}
another way is to add OnException event on your BaseController which will detect any error or exception, hence you can log it without try-catch blocks, do it as following:
define this in your baseController: ExceptionLogger Err = new ExceptionLogger(); with its using then add the event:
protected override void OnException(ExceptionContext filterContext)
{
var isSent = false;
if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
{
return;
}
if (new HttpException(null, filterContext.Exception).GetHttpCode() != 500)
{
return;
}
if (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
{
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
error = true,
message = filterContext.Exception.Message
}
};
LogError("Controller: AjaxCall" + " Action: AjaxCall" + filterContext.Exception.Message, filterContext.Exception);
}
else if (filterContext.Exception is HttpAntiForgeryException)
{
Response.Clear();
Server.ClearError(); //make sure you log the exception first
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(new { action = "Logout", controller = "Account" }));
}
else
{
var controllerName = (string)filterContext.RouteData.Values["controller"];
var actionName = (string)filterContext.RouteData.Values["action"];
var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
if (actionName == "_Menu")
{
isSent = true;
Response.Redirect("~/Account/Logout");
}
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Error/Error.cshtml",
MasterName = null,
ViewData = new ViewDataDictionary(model),
TempData = filterContext.Controller.TempData
};
////Redirect or return a view, but not both.
LogError("Controller: " + controllerName + " Action: " + actionName + filterContext.Exception.Message, filterContext.Exception);
}
// log the error by using your own method
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
if (isSent == false)
{
filterContext.HttpContext.Response.StatusCode = 500;
}
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
private void LogError(string message, Exception exception)
{
Err.ErrorLog(message + " && " + exception.Message);
}
now when errors happen then you will go to c:/logfiles folder in the server and find the exact error happened

Exception Logging Without using try catch - ASP.NET WEB API

I need to log exceptions and bad requests in my API. Currently I am using try catch to catch the exception and add to my logs in the catch block. Is this the right way? I read about Global Error Handling in ASP.NET. How can I implement that approach for this case?
Below is my API Controller example:
[HttpPost]
[Authorize]
[ValidateModel]
[Route("CheckProgramOwner")]
public async Task<IHttpActionResult> CheckProgramOwner([FromBody] CheckProgramOwner _data)
{
try
{
using (var db = new VisualVoiceFlowEntities())
{
var Result= await db.VVF_ScriptFlow.Where(s => s.ProgramId == _data.ProgramId).OrderByDescending(s => s.ID).FirstOrDefaultAsync();
if(Result== null)
{
Log.Error("Error in CheckProgramOwner POST Request - " + "ProgramId not found");
return Content(HttpStatusCode.BadRequest, "ProgramId not found");
}
string CurrentOwner = Result.ReadBy.ToString();
return Ok(CurrentOwner);
}
}
catch (Exception ex)
{
Log.Error("Error in CheckProgramOwner POST Request - " + ex.Message, ex);
NewRelic.Api.Agent.NewRelic.NoticeError("Error in CheckProgramOwner POST Request - " + ex.Message, null);
return Content(HttpStatusCode.InternalServerError, "Internal Server Error. Please Contact Admin.");
}
}
If you read the document previously posted by Casey, you will find a link to the following document, which explains how to implement and register an exception filter globally:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/error-handling/exception-handling#registering_exception_filters
You could then implement your logging logic in the filter's body thus avoiding having to repetitively log errors on each try/catch. I would suggest logging the more obvious errors using your original approach and use the filter to log any other errors (that you might not expect.)
I did it using ExceptionFilter.
I created Exception Filter Class as below -
public class MyExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
log4net.ThreadContext.Properties["addr"] = HttpContext.Current.Request.UserHostAddress;
log4net.ThreadContext.Properties["Hostname"] = Dns.GetHostName().ToString();
log4net.ThreadContext.Properties["PCName"] = Dns.GetHostAddresses(Environment.MachineName)[0].ToString();
string RequestMethod = context.Request.Method.Method;
dynamic ControllerInfo = context.ActionContext.ControllerContext.Controller;
string RequestName = ControllerInfo.Url.Request.RequestUri.LocalPath.ToString().Replace("/api/", "").Replace("/VVFAPI", "");
Log.Error("Error in " + RequestName +" "+ RequestMethod+ " Request - " + context.Exception.Message, context.Exception);
NewRelic.Api.Agent.NewRelic.NoticeError("Error in " + RequestName + " " + RequestMethod + " Request - " + context.Exception.Message, null);
HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("Internal Server Error. Please Contact Admin."),
ReasonPhrase = "Critical Exception."
};
context.Response = msg;
}
}
Also, I changed my controller accordingly
[HttpPost]
[Authorize]
[ValidateModel]
[MyExceptionFilter]
[Route("CheckProgramOwner")]
public async Task<IHttpActionResult> CheckProgramOwner([FromBody] CheckProgramOwner _data)
{
Log.Info("CheckProgramOwner POST Request");
using (var db = new VisualVoiceFlowEntities())
{
var Result = await db.VVF_ScriptFlow.Where(s => s.ProgramId == _data.ProgramId).OrderByDescending(s => s.ID).FirstOrDefaultAsync();
if (Result == null)
{
Log.Error("Error in CheckProgramOwner POST Request - " + "ProgramId not found");
return Content(HttpStatusCode.BadRequest, "ProgramId not found");
}
string CurrentOwner = Result.ReadBy.ToString();
return Ok(CurrentOwner);
}
}

frmMain is inaccessible due to its protection level

OK this is what I have. I have my main form frmMain.cs and I have a class.cs. I was doing an RSSFeed for my email and I get the error:
inaccessible due to its protective level.
On my class.cs I have the following code:
public class RSSFeed
{
public void CheckForEmails()
{
string GmailAtomUrl = "https://mail.google.com/mail/feed/atom";
XmlUrlResolver xmlResolver = new XmlUrlResolver();
xmlResolver.Credentials = new NetworkCredential(Settings.Default.GmailUser, Settings.Default.GmailPassword);
XmlTextReader xmlReader = new XmlTextReader(GmailAtomUrl);
xmlReader.XmlResolver = xmlResolver;
try
{
XNamespace ns = XNamespace.Get("http://purl.org/atom/ns#");
XDocument xmlFeed = XDocument.Load(xmlReader);
var emailItems = from item in xmlFeed.Descendants(ns + "entry")
select new
{
Author = item.Element(ns + "author").Element(ns + "name").Value,
Title = item.Element(ns + "title").Value,
Link = item.Element(ns + "link").Attribute("href").Value,
Summary = item.Element(ns + "summary").Value
};
frmMain.MsgList.Clear();
frmMain.MsgLink.Clear();
foreach (var item in emailItems)
{
if (item.Title == String.Empty)
{
frmMain.MsgList.Add("Message from " + item.Author + ", There is no subject and the summary reads, " + item.Summary);
frmMain.MsgLink.Add(item.Link);
}
else
{
frmMain.MsgList.Add("Message from " + item.Author + ", The subject is " + item.Title + " and the summary reads, " + item.Summary);
frmMain.MsgLink.Add(item.Link);
}
}
if (emailItems.Count() > 0)
{
if (emailItems.Count() == 1)
{
frmMain.lblEmail.Text = ("You have one new email, would you like me to read it to you");
}
else
{
frmMain.lblEmail.Text("You have " + emailItems.Count() + "new emails");
}
}
else if (frmMain.QEvent == "CheckForNewEmails" && emailItems.Count() == 0)
{
frmMain.lblEmail.Text("You have no new emails"); frmMain.QEvent = String.Empty;
}
}
catch
{
frmMain.lblEmail.Text("You have submitted invalid log in information");
}
}
}
And then I have on my main form a timer tick event:
public void tmrEmail_Tick(object sender, EventArgs e)
{
lblEmail.Text = ("New Emails " + RSSFeed.CheckForEmails);
}
What I am not understanding is when I have the label in my RSSFeed or on my main form timer tick. I get the error. I have changed everything to public and it still is throwing the error.
Am I missing something or do I not have everything I should have?
Also I am going to have another form that is just dedicated to email. Would it be better to do away with the RSSFeed.cs and just code the winform? The only thing this is doing is creating a label when I have new emails.
Any thoughts?
You are missing the static keyword from your class and method. Should be public static class RSSFeed and public static void CheckForEmails()
You need to pass an instance of the frmMain to the method too. E.g.:
public static void CheckForEmails(frmMain frmMainInstance)
Putting it all together:
public static class RSSFeed
{
public static void CheckForEmails(frmMain frmMainInstance)
{
string GmailAtomUrl = "https://mail.google.com/mail/feed/atom";
XmlUrlResolver xmlResolver = new XmlUrlResolver();
// ... rest of your code ...
}
}
And the call to it would be something like:
public void tmrEmail_Tick(object sender, EventArgs e)
{
// The following line will produce a compile error because
// CheckForEmails doesn't return a value
// lblEmail.Text = ("New Emails " + RSSFeed.CheckForEmails(this);
// Try this instead:
RSSFeed.CheckForEmails(this);
}
Note that I am assuming tmrEmail_Tick is a method in frmMain, hence I am passing this as the argument to CheckForEmails.
Instead of making RSSFeed and CheckForEmails static you could instantiate an instance of RSSFeed:
public void tmrEmail_Tick(object sender, EventArgs e)
{
RSSFeed feed = new RSSFeed();
feed.CheckForEmails(this);
}
Note that you still need to pass frmMain instance as an argument to CheckForEmails.

Ambiguous match error when calling overloaded .asmx methods dynamically

I am using reflection and WSDL to call web services on the fly through dynamically constructed proxy classes, and I have just added some overloaded web methods to one of the web services I am calling. Now I get an 'Ambigious match' error when trying to Invoke (via reflection) the method.
Here is the class that builds the service proxy and has a method to invoke any given web method in that proxy by name:
public class ServiceProxy
{
public ServiceMetadata Metadata { get; private set; }
public RemoteServiceElement Element { get; private set; }
public string IpAddress { get; private set; }
private object serviceProxy;
private string serviceAsmx;
public ServiceProxy(RemoteServiceElement element)
{
IpAddress = element.IpAddress;
Element = element;
serviceAsmx = "http://" + element.IpAddress + ":" + element.Port + "xxxx.asmx"
Build(serviceAsmx, "xxxx");
}
public ServiceProxy(string ip, string _asmx, string _serviceName)
{
IpAddress = ip;
serviceAsmx = _asmx;
Build(_asmx, _serviceName);
}
private void Build(string webServiceAsmx, string serviceName)
{
WebClient client = new WebClient();
Metadata = ServiceMetadata.OpenWsdl(webServiceAsmx);
Stream stream = client.OpenRead(webServiceAsmx + "?wsdl");
ServiceDescription description = ServiceDescription.Read(stream);
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
importer.ProtocolName = "Soap12";
importer.AddServiceDescription(description, null, null);
importer.Style = ServiceDescriptionImportStyle.Client;
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties;
CodeNamespace nmspace = new CodeNamespace();
CodeCompileUnit unit1 = new CodeCompileUnit();
unit1.Namespaces.Add(nmspace);
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit1);
if (warning == 0)
{
CodeDomProvider provider1 = CodeDomProvider.CreateProvider("CSharp");
string[] assemblyReferences = new string[5] { "System.dll", "System.Web.Services.dll", "System.Web.dll",
"System.Xml.dll","System.Data.dll" };
CompilerParameters param = new CompilerParameters(assemblyReferences);
CompilerResults results = provider1.CompileAssemblyFromDom(param, unit1);
if (results.Errors.Count > 0)
{
foreach (CompilerError err in results.Errors)
{
Logger.Write("Compiler error assembling " + webServiceAsmx + " - " + err.ErrorText);
}
throw new Exception("Compiler error occurred calling the web service. Check log for details.");
}
serviceProxy = results.CompiledAssembly.CreateInstance(serviceName);
Logger.Write("Proxy service at + " + serviceAsmx + " assembled successfully");
}
}
public object Invoke(string methodName, object[] args = null)
{
MethodInfo info = serviceProxy.GetType().GetMethod(methodName);
object asmxResults = default(object);
try
{
asmxResults = info.Invoke(serviceProxy, args);
Logger.Write("Remote proxy at " + serviceAsmx + " - " + methodName + " - " + "invoked successfully");
}
catch (Exception e)
{
Logger.Write("Error invoking proxy class at " + serviceAsmx + " - " + e.InnerException);
}
return asmxResults;
}
}
This worked fine before I added any overloads. So I am guessing that using reflection + overloads may be causing an issue.
Here is a mock-up example of one of the WebMethods that causes the problem:
[WebMethod (MessageName="GetFoos")]
public List<Foo> GetFoos(DateTime dt)
{
// performs linq query
}
[WebMethod (MessageName = "GetFoosDynamic")]
public List<Foo> GetFoos(Expression exp)
{
// linq query
}
Same method name, different parameters + different 'MessageName' which is supposed to work for web services.
Thanks for any help.
SOAP doesn't support method overloading, but it looks like you've overridden your method name with the WebMethod attribute, so you should be calling the names you've defined within that attribute when you make your SOAP call.

Categories

Resources