Determine if CoreApplicationView.GetCurrentView() will throw exception? - c#

Early in uwp app startup, CoreApplicationView.GetCurrentView() may throw an exception, presumably because there isn't a current view yet.
Is there a way to tell if that will happen or not, without actually calling it?

I haven't tested it, but CoreApplication.Views returns a list of all existing views. It should be possible to do something like that:
public static bool HasCurrentView() {
return CoreApplication.Views.Count > 0;
}
I couldn't test it cause I don't know when this exactly throws an exception.

The CoreApplicationView.GetCurrentView() method returns the active view for the app. I think you need to add a judgement before calling it.
For example like this:
if (Window.Current != null)
{
if (Window.Current.Content != null)
{
Window.Current.Activate();
var view = CoreApplication.GetCurrentView();
}
}

Related

C# lambda null runtime binding

I'm running into an odd scenario that doesn't happen on my PC, but does for a coworkers.
I have this piece of code:
LoaderHelpers.SetStringValue<blah>(this, "x", $"x response in Header",
() => jsonData.x.response[0].value, false);
The problem is that sometimes, "jsonData.x" is null and, for my coworker a 'cannot bind to null at runtime exception' is thrown, but not for me there isn't. I have code to handle the null scenario, but it's like his code never gets to that point and fails at the call level.
jsonData is of type dynamic.
The method code that handles the null scenario:
public static void SetStringValue<T>(IValidate data, string propertyName,
string valuePath, Func<string> value, bool required)
{
if (data.GetType().GetProperty(propertyName) != null)
{
try
{
if (string.IsNullOrEmpty(value()))
{
if (required)
data.DataValidationErrors.Add($"{valuePath} can't be empty");
data.GetType().GetProperty(propertyName).SetValue(data, null);
}
else
{
data.GetType().GetProperty(propertyName).SetValue(data, value());
}
}
catch
{
//property doesn't exist
if (required)
data.DataValidationErrors.Add($"{valuePath} doesn't exist");
data.GetType().GetProperty(propertyName).SetValue(data, null);
}
}
else
{
throw new NullReferenceException($"In {data.GetType()} => SetStringValue. " +
$"Passed property {propertyName}, but property doesn't exist.");
}
}
Again. Works perfect for me, but not for him. I'm completely lost. Maybe I don't understand how the lamba/function parameters work 100%, but I thought it only got evaluated when value() is invoked.
I should also mention that when I debug this code, I can step into the Nuget package and when he hits the same line, he can't. This maybe a useful hint.
If jsonData (or jsonData.x) is null (as it seems to be at this point) it will crash and give you that error every time you call the method value().
You need to check why jsonData.x is null. Maybe it´s a race condition caused by another thread setting this value to null, maybe it´s because a bad jsonData initialization... Can´t say since that code is not here.
There are so many things wrong with your code, i can't resist.
First of all, instead of copy/pasting the same stuff over and over, you might want to use a variable:
var property = data.GetType().GetProperty(propertyName);
Second, you pass a Func<string> and execute it multiple times, why is it even a function then? Yet again, better only evaluate it once and use a variable...
var unwrapped = value();
That would solve the issue, that Roberto Vázquez' answer adresses.
Then you are misusing NullReferenceException, instead rather use a ArgumentException
Next issue, that valuePath is only used in the exception message, that is a poor design to my beliefs.
The generic T parameter isnt even used, so get rid of it.
Last but not least, that catch-block doing the exact thing that could possibily throw the exception again, i cant see any reason why you would do this.
Finnaly this whole thing becomes a little more clear but its still a mess.
public static void SetStringValue(IValidate data, string propertyName,
string valuePath, Func<string> value, bool required)
{
if(data == null)
throw new ArgumentNullException(nameof(data));
var property = data.GetType().GetProperty(propertyName);
if(property == null)
throw new ArgumentException($"In {data.GetType()} => SetStringValue. " +
$"Passed property {propertyName}, but property doesn't exist.");
var unwrapped = value();
try
{
if (string.IsNullOrEmpty(unwrapped))
{
if (required)
data.DataValidationErrors.Add($"{valuePath} can't be empty");
unwrapped = null; // this might be unecessary.
}
property.SetValue(data, unwrapped);
}
catch(Exception e)
{
// This is probably a bad idea.
property.SetValue(data, null);
if (required)
data.DataValidationErrors.Add(Atleast put a better message here. e.Message ...);
}
}

Issues with Nancy Framework for MVC (and NewRelic)

I just took over a bunch of C# code from another company, and I'm having big trouble getting the first build to work. The code uses a framework called Nancy, instead of MVC. I have never used this framework before, and there might be a real simply answer to my question, and I apllogize if I missed some basic understanding of Nancy, before posting here.
The problem is boiled down to a single class, handling the initialization of the application (I THINK) From what I've read, it's pretty standard Nancy:
using System;
using Nancy;
using NewRelicAgent = NewRelic.Api.Agent.NewRelic;
using Nancy.Bootstrapper;
using Nancy.Routing;
public class NewRelicStartup : IApplicationStartup
{
private readonly IRouteResolver routeResolver;
public NewRelicStartup (IRouteResolver routeResolver)
{
this.routeResolver = routeResolver;
}
public void Initialize(IPipelines pipelines)
{
pipelines.BeforeRequest.AddItemToStartOfPipeline(
context =>
{
var route = routeResolver.Resolve(context);
if (route == null || route.Item1 == null || route.Item1.Description == null) // probably not necessary but don't want the chance of losing visibility on anything
{
NewRelicAgent.SetTransactionName(
context.Request.Method,
context.Request.Url.ToString());
}
else
{
NewRelicAgent.SetTransactionName(
route.Item1.Description.Method,
route.Item1.Description.Path);
}
return null;
});
pipelines.OnError.AddItemToEndOfPipeline(
(context, ex) => {
NewRelicAgent.NoticeError(ex);
return null;
}
);
}
}
When this code is being build, I get several errors, some of which being:
Delegate 'System.Func<Nancy.NancyContext,System.Threading.CancellationToken,System.Threading.Tasks.Task<Nancy.Response>>' does not take 1 arguments
Cannot convert lambda expression to type 'Nancy.PipelineItem<System.Func<Nancy.NancyContext,System.Threading.CancellationToken,System.Threading.Tasks.Task<Nancy.Response>>>' because it is not a delegate type
Here is a screenshot of the kind of error I get:
https://www.dropbox.com/s/cigcfc4sfj8batg/Nancy%20Error.PNG
I am 100 % certain, that this is some kind of interpretation issue from Visual Studio's side, since the code is live atm. I just can't build it in VS.
Do any of you have any idea what I am missing, or doing wrong? Remember; the code is working and live atm.
Try changing "return null;" to "return (Nancy.Response)null;"
Edit: Sorry, just looked at the screenshot - it's using some properties that have changed in 0.20, so you will either have to manually fix up the code (it's now async at the core), or roll back to 0.19 for now, and re-write that bit of code at a later date.
Edit again: Give this ago:
pipelines.BeforeRequest.AddItemToStartOfPipeline(
context =>
{
var route = routeResolver.Resolve(context);
if (route == null || route.Route == null || route.Route.Description == null) // probably not necessary but don't want the chance of losing visibility on anything
{
NewRelicAgent.SetTransactionName(
context.Request.Method,
context.Request.Url.ToString());
}
else
{
NewRelicAgent.SetTransactionName(
route.Route.Description.Method,
route.Route.Description.Path);
}
return null;
});

Intents in mvvmcross on Mono for Android

I've recently upgraded to Xamarin Studio running on Windows. I have a simple implementation of the mvvmcross TipCalculator tutorial that ran nicely on Android and the various Windows flavors. After I upgraded, the Android application started throwing NullReferenceExceptions in the Main activity (below):
[Activity(Label = "TipCalculator.Android", MainLauncher = true, Icon = "#drawable/icon")]
public class TipCalculatorActivity : MvxBindingActivityView<TipCalculatorViewModel>
{
protected override void OnViewModelSet()
{
SetContentView(Resource.Layout.TipView);//Throws NullReferenceException
}
}
After doing some digging into the mvvmcross code, I found this method in the MvxAndroidViewsContainer class:
public virtual IMvxViewModel Load(Intent intent, Type viewModelTypeHint)
{
if (intent == null)
{
// TODO - some trace here would be nice...
return Activator.CreateInstance(viewModelTypeHint) as IMvxViewModel;
//return null;
}
if (intent.Action == Intent.ActionMain)
{
// TODO - some trace here would be nice...
return Activator.CreateInstance(viewModelTypeHint) as IMvxViewModel;
}
if (intent.Extras == null)
{
// TODO - some trace here would be nice...
return Activator.CreateInstance(viewModelTypeHint) as IMvxViewModel;
//return null;
}
IMvxViewModel mvxViewModel;
if (TryGetEmbeddedViewModel(intent, out mvxViewModel))
return mvxViewModel;
return CreateViewModelFromIntent(intent);
}
In the original code, there are two cases that return null. In each of these I replaced that with a call to Activator.CreateInstance().
I'm not sure what the rationale behind the original implementation is, and I'm a bit concerned I've broken something. Can anybody shed some light on why there are cases this method returns null and whether I've broken something fundamental in mvvmcross?
I have no idea what your current issue has to do with the new Xamarin tools. Your description of NullReferenceExceptions, changed files and blog posts lost me...
I'd guess that quite a few things may have changed in your development setup and maybe in your app as well. If you can work back out one step at a time maybe then you'll be able to work out what the key change is.
It does sound like your code change might fix might fix your current problem - but it's definitely a patch applied after the problem (whatever it is) has occurred, so it's not something I'd want to do in the core code right now.
In terms of the code you've asked about:
if (intent == null)
{
// TODO - some trace here would be nice...
return null;
}
This first null will only occur if the Activity has somehow been created without an Intent - which I guess isn't happening? (Unless maybe somewhere in your current tooling setup this is somehow being set as null?)
if (intent.Action == Intent.ActionMain)
{
// TODO - some trace here would be nice...
return Activator.CreateInstance(viewModelTypeHint) as IMvxViewModel;
}
This is the normal path for a directly launched activity - this activity will have no extra parameters for constructing the ViewModel.
Generally this path doesn't happen in many MvvmCross apps - most apps launch via a splashscreen activity.
if (intent.Extras == null)
{
// TODO - some trace here would be nice...
return null;
}
For any other activity, Mvx should have inserted some special ViewModel information into the Extras - so there is no way Extras should be null... If this is happening, then what code is creating the activity?
IMvxViewModel mvxViewModel;
if (TryGetEmbeddedViewModel(intent, out mvxViewModel))
return mvxViewModel;
return CreateViewModelFromIntent(intent);
This is the normal launch path for an activity that has been navigated to.
If it helps, here's the latest v3 code - which has some trace added (but also adds the confusion of savedState - ignore this for now!):
public virtual IMvxViewModel Load(Intent intent, IMvxSavedState savedState, Type viewModelTypeHint)
{
if (intent == null)
{
MvxTrace.Trace(MvxTraceLevel.Error, "Null Intent seen when creating ViewModel");
return null;
}
if (intent.Action == Intent.ActionMain)
{
MvxTrace.Trace("Creating ViewModel for ActionMain");
return Activator.CreateInstance(viewModelTypeHint) as IMvxViewModel;
}
if (intent.Extras == null)
{
MvxTrace.Trace(MvxTraceLevel.Error, "Null Extras seen on Intent when creating ViewModel - this should not happen - have you tried to navigate to an MvvmCross View directly?");
return null;
}
IMvxViewModel mvxViewModel;
if (TryGetEmbeddedViewModel(intent, out mvxViewModel))
{
MvxTrace.Trace("Embedded ViewModel used");
return mvxViewModel;
}
MvxTrace.Trace("Loading new ViewModel from Intent with Extras");
return CreateViewModelFromIntent(intent, savedState);
}

Null check returns true for non-null value

Having an odd problem. It's happened a few times over the years, but I've never been able to figure out why. Always solved it by rearranging the code I had in place, but would like to know is there's a more proper way of dealing with it, or at least figuring out what's behind it.
Non-working version:
public bool CaptureFrame(ArrayCache cache)
{
if (cache == null)
throw new ArgumentNullException("cache");
DataArray frame = cache.CacheData;
if (frame == null)
throw new ArgumentNullException("cache.CacheData");
// do stuff
}
Working version:
public bool CaptureFrame(ArrayCache cache)
{
if (cache == null)
throw new ArgumentNullException("cache");
if (cache.CacheData == null)
throw new ArgumentNullException("cache.CacheData");
DataArray frame = cache.CacheData;
// do stuff
}
The problem is this: frame is not null (at least according to the debugger, and by any measure I can trace of the code), however when it does the if (frame == null) check, it comes out true and throws the exception. I rewrote to check cache.CacheData and it works fine, but it really shouldn't make any difference to the code logic.
I managed to find one other question on the site with a similar problem, which ended up being related to the == and != operators being overloaded. Those operators are not overloaded for the class in question in my code, and it's a standalone class so there's nothing for it to inherit.
Edit: John Saunders requested code for the CacheData property:
private DataArray cacheData;
public DataArray CacheData
{
get
{
return cacheData;
}
set
{
cacheData = value;
}
}
looks like you are mapping the exception in the non working one then calling
DataArray frame = cache.CacheData;
but what if cache.CacheData if null then you are assigning it to DataFrame.. it's always best in my opinion to do the Check for null first before assigning or assuming your second one looks fine.. prehaps instead of throwing an exception maybe you could trap the exception and try some test cases for both scenarios

Workaround for HttpContext.HideRequestResponse being internal? Detect if HttpContext.Request is really available?

We're migrating an application to use IIS7 integrated mode. In library code that is designed to work either within the context of an HTTP request or not, we commonly have code like this:
if (HttpContext.Current != null &&
HttpContext.Current.Request != null) {
// do something with HttpContext.Current.Request
} else {
// do equivalent thing without HttpContext..
}
But in IIS7 integrated mode the check for HttpContext.Current.Request throws an exception whenever this code is called from Application_Start.
protected void Application_Start(object sender, EventArgs e)
{
SomeLibrary.DoSomethingWithHttpContextCurrentDetection();
}
Results in:
System.Web.HttpException: Request is not available in this context
How can I detect whether the request is really available without wrapping these calls in an exception handler and taking action based on whether an exception is generated or not.
Looking at HttpContext in Reflector I see it has an internal bool HideRequestResponse field but it's internal so I can only get to it with reflection and that's fragile. Is there a more official/approved way to determine if it's ok to call HttpContext.Request?
This blog post about the subject says not to use HttpContext, but how, in generic library code, can you determine if it's ok to use HttpContext?
http://mvolo.com/iis7-integrated-mode-request-is-not-available-in-this-context-exception-in-applicationstart/
I'm using the work-around mentioned there which is to use Application_BeginRequest and an initialized field to only initialize once as part of BeginRequest, but that has to be done in every calling application whereas I'd prefer to make the library code more robust and handle this situation regardless of where it's called from.
I would refactor your code to this:
if (IsRequestAvailable())
{
// do something with HttpContext.Current.Request...
}
else
{
// do equivalent thing without HttpContext...
}
public Boolean IsRequestAvailable()
{
if (HttpContext.Current == null)
return false;
try
{
if (HttpContext.Current.Request == null)
return false;
}
catch (System.Web.HttpException ex)
{
#if DEBUG
// Testing exception to a magic string not the best practice but
// it works for this demo.
if (ex.Message == "Request is not available in this context")
return false;
throw;
#else
return false;
#endif
}
return true;
}
Your question asked not to use exception handling (I assume for performance reasons) and my answer does. However, by changing your code from using "If (HttpContext.Current != null && HttpContext.Current.Request != null)" to "If (IsRequestAvailable())" you only have one place to change the code when you find an answer how not to use exception handling.
I'm afraid the answer is that you can't get what you want - Microsoft sees this case as an 'exceptional circumstance' and so it will throw an exception.
You can use reflection as you describe in your answer but you don't want to and so are limited by the API that Microsoft have provided, for better or for worse.
If you do decide to use reflection, of note is the HttpApplication.InitInternal method which is what sets the HideRequestResponse flag.
Hope that helps. I would suggest you file a report with Microsoft Connect.
You should not even use Request (or Response) in the Application_Start since application could be started without a request. So in the future your application won't even run when other parts of framework stop providing the Request object.
If you want to just hack it temporarily, you could use Reflection (if you have above-medium trust) or catching an exception (even though you don't want to) and store the result in a static variable or possibly use a static HttpContext wrapper:
Also you could use HttpRuntime.UsingIntegratedPipeline.
So the best approach is remove the dependance of your classes on HttpContext when they are being initialized or not initalize them in appstart.
What is your reasoning to use Request in the app start anyway? For statistics? Or just telling the user he woke the application?
Edited with code to explain better:
public static class ContextWrapper
{
public static HttpRequest Request
{
get
{
HttpContext context = HttpContext.Current;
if (context == null) return null;
if (HttpRuntime.UsingIntegratedPipeline)
{
try { return context.Request; }
catch (HttpException e) { /* Consume or log e*/ return null; }
// Do not use message comparison - .NET translates messages for multi-culture environments.
}
return context.Request;
}
}
}
And in code:
if (ContextWrapper.Request != null) //...
Or a user-controlled faster way:
public static class ContextWrapper2
{
public static bool IsIis7IntegratedAppStart { get; set; }
public static HttpRequest Request
{
get
{
if (ContextWrapper2.IsIis7IntegratedAppStart) return null;
HttpContext context = HttpContext.Current;
if (context == null) return null;
return context.Request;
}
}
}
And in app start:
protected void Application_Start(object sender, EventArgs e)
{
yourLibraryNamespace.ContextWrapper2.IsIis7IntegratedAppStart = true;
//...
yourLibraryNamespace.yourClass.Init();
//...
yourLibraryNamespace.ContextWrapper2.IsIis7IntegratedAppStart = false;
}
You could note this behaviour in your documentation and all should be well. AppStart-like context should be the only place where you get such an exception.
You could also implement IDisposable on a member and use it in appStart with the using statement so you do not forget to set IsIis7IntegratedAppStart = false.
I think I have the solution for you. I maintain a logging library and have the same issue as you. If it is a web request I am grabbing some data from the HttpContext. But depending on how the logging library is used this same scenario can happen. So here is my solution. The key fix for me was checking if the Handler was null or not.
if (System.Web.Hosting.HostingEnvironment.IsHosted
&& System.Web.HttpContext.Current != null
&& System.Web.HttpContext.Current.Handler != null
&& System.Web.HttpContext.Current.Request != null)
{
//access the Request object here
}
Depending on what you are trying to accomplish, you may be able to get some of the properties and settings around the web app from System.Web.Hosting.HostingEnvironment
I added a comment, but it gets auto-hidden.
I think it's more important to have an idea of what it is that you need from the request.
For instance, the link you provided which provides a workaround is looking for Request.ApplicationPath.
If that's actually what you're looking for (for, say, loading the web.config vs the app.config), you could do this:
if (HttpRuntime.AppDomainAppId != null)
return WebConfigurationManager.OpenWebConfiguration(HttpRuntime.AppDomainAppVirtualPath);
else
return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
If this (or HttpRuntime.ApplicationPath) isn't what you're actually looking for, it would be helpful to know which properties of the Request you are actually looking for. Maybe there's a better, safer way to get there.

Categories

Resources