NullReferenceException on *setting* value in ViewBag - c#

I'm at my wit's end here. I keep getting a NullReferenceException on the following line of code:
ViewBag.PaypalError = "we were unable to retreive your cart.";
I know it's that line - I added some code elsewhere in the file which caused it to get a new line number, and the line number in my error changed to follow it. I know ViewBag is not null, because I specifically inserted an if (ViewBag == null) test before it.
To make matters weirder, I have code to send an email when execution enters the logic that leads to the above statement. That email never gets set, yet this line of code, which happens afterwards, throws an exception, and I get the email from the try/catch block that catches it.
I know I should probably just eschew ViewBag, and I have some ideas for refactoring the code to not need it here, but none of that tells me where this exception is coming from.
Any ideas? Tests to try?
Edit:
Here's the rest of the code. It's definitely not code I'm proud of, but it ought to work...
public ActionResult PaypalConfirmation(string token, string payerID)
{
try
{
Cart cart = GetCurrentCart();
if (cart == null)
{
// I never get this email.
SendEmail("Paypal confirmation with null cart", "Token: " + token + ".<br><br>", requestData: Request);
if (token != null && token != "")
{
var tempCart = Cart.GetByAlternateOrderNumber(token);
if (tempCart != null)
{
cart = tempCart;
}
else
{
ViewBag.PaypalError = "we were unable to retreive your cart.";
return View("~/Views/Error/PayPal.cshtml");
}
}
else
{
if (ViewBag == null)
{
SendEmail("VIEWBAG WAS NULL", "Token: " + token + ".<br><br>", requestData: Request);
return View("~/Views/Error/PayPal.cshtml");
}
else
{
// Line which errors
ViewBag.PaypalError = "we were unable to retreive your cart.";
return View("~/Views/Error/PayPal.cshtml");
}
}
}
// More execution code here, including the "Everything worked" return.
}
catch (Exception ex)
{
try
{
var isNull = "";
if (ViewBag == null) isNull = "ViewBag was null!<br><br>";
SendEmail("Crash in Paypal Payment", isNull + ex.ToString(), requestData: Request);
return View("~/Views/Error/PayPal.cshtml");
}
catch (Exception ex2)
{
SendEmail("Crash in reporting Paypal Crash!", ex.ToString() + "<br><br>---------------------<br><br>" + ex2.ToString());
return View("~/Views/Error/PayPal.cshtml");
}
}
}
Email from the catch block:
System.NullReferenceException: Object reference not set to an instance of an object. at Website.Controllers.CartController.PaypalConfirmation(String token, String payerID) in C:#############\Website\Controllers\CartController.cs:line 137
Timestamp: 3/6/2012 10:43:13 AM
IP: #############
URL Requested: /Cart/PaypalConfirmation?token=EC-10L01937X56050826&PayerID=############
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0.2) Gecko/20100101 Firefox/10.0.2

I doubt this is coming from ViewBag being null. When you add or remove lines, it changes the line numbers of everything below it. So it could have been any code below what you changed. If the new code required you to add a new using statement to the class, it could have changed every line number in the output bytecode.
Have you tried using email as a form of logging instead of just exception catching? For example, what happens when you try this? Not sure whether the ex.Source property would help?
public ActionResult PaypalConfirmation(string token, string payerID)
{
var message = "Trying to confirm paypal.";
SendEmail(message, message);
try
{
message = "Getting current cart.";
SendEmail(message, message);
Cart cart = GetCurrentCart();
message = cart == null
? "Current cart is null."
: "Current cart is not null.";
SendEmail(message, message);
if (cart == null)
{
if (token != null && token != "")
{
message = "Getting temp cart by alternate order number.";
SendEmail(message, message);
var tempCart = Cart.GetByAlternateOrderNumber(token);
message = "Getting temp cart by alternate order number.";
SendEmail(message, message);
if (tempCart != null)
{
message = "Temp cart is not null";
SendEmail(message, message);
cart = tempCart;
}
else
{
message = "Temp cart was null.";
SendEmail(message, message);
ViewBag.PaypalError = "we were unable to retreive your cart.";
message = "ViewBag.PayPalError set, returning view.";
SendEmail(message, message);
return View("~/Views/Error/PayPal.cshtml");
}
}
else
{
message = "Setting ViewBag.PayPalError message.";
SendEmail(message, message);
// Line which errors
ViewBag.PaypalError = "we were unable to retreive your cart.";
message = "ViewBag.PayPalError set, returning view.";
SendEmail(message, message);
return View("~/Views/Error/PayPal.cshtml");
}
}
// More execution code here, including the "Everything worked" return.
message = "Executing more code.";
SendEmail(message, message);
}
catch (Exception ex)
{
SendEmail(ex.GetType().Name + " caught", ex.Source);
return View("~/Views/Error/PayPal.cshtml");
}
}

Related

How can I use delegates/lambdas/Func<> to get rid of code reuse?

I have a web service where I find myself putting the exact same try/catch block in every method and I'm trying to eliminate that code reuse.
Here is a sample method (some code removed) where you can see #1/#2/#3 are the core calls and are very similar.
[HttpGet]
[Route("GetKeys")]
[Produces(MediaTypeNames.Application.Json)] // "application/json"
public async Task<EntityKeyPage> GetKeys([FromQuery] string company = "", [FromQuery] DocumentPaging documentPaging = null)
{
[...]
try
{
// Sometimes it's this #1
VendTableServiceGetKeysResponse getKeysResponse = await aifClient.getKeysAsync(getKeysRequest);
// Sometimes it's this #2
// VendTableServiceReadResponse readResponse = await aifClient.readAsync(readRequest);
// Sometimes it's this #3
// VendTableServiceFindKeysResponse findKeysResponse = await aifClient.findKeysAsync(findKeysRequest);
}
catch (System.ServiceModel.FaultException<AifFault> ex)
{
var message = this.GetAXMessage(ex);
aifClient.Abort();
throw new Exception(message);
}
catch (Exception e)
{
aifClient.Abort();
string errorMessage = e.Message != null ? e.Message : "";
errorMessage = e.InnerException != null ? errorMessage + "\n" + e.InnerException : errorMessage;
throw new Exception(errorMessage);
}
finally
{
aifClient.Close();
}
return getKeysResponse.EntityKeyPage;
}
Here is my attempt at a generic method I can use.
private async Task<Out> MakeAIFCall<In, Out>(Func<In, Out> action, In #in)
{
Out #out;
try
{
#out = action(#in);
}
catch (System.ServiceModel.FaultException<AifFault> ex)
{
var message = this.GetAXMessage(ex);
aifClient.Abort();
throw new Exception(message);
}
catch (Exception e)
{
aifClient.Abort();
string errorMessage = e.Message != null ? e.Message : "";
errorMessage = e.InnerException != null ? errorMessage + "\n" + e.InnerException : errorMessage;
throw new Exception(errorMessage);
}
finally
{
aifClient.Close();
}
return #out;
}
I wrote that method based on my reading, but I can't figure out how to call it? It appears I normally would pass a method name, but in this case it would be an object+method (aifClient.getKeysAsync(...)/aifClient.readAsync(...)/aifClient.findKeysAsync(...))?
How do I call my method and or am I doing it wrong?
This is my first attempt at calling it, but it's wrong:
var response = await MakeAIFCall<VendTableServiceGetChangedKeysRequest, VendTableServiceGetChangedKeysResponse>(aifClient.getKeysAsync, getKeysRequest);
The variables #out and #in were suggested by intellisense...I have no idea why the # symbol is there or what it does.
Since your methods are awaited we can almost safely assume that they return tasks (however there are other possibilities), so first of all you will need to change your method signature to something like this:
private async Task<Out> MakeAIFCall<In, Out>(Func<In, Task<Out>> action, In #in)
{
Out #out;
try
{
#out = await action(#in);
}
....
Second of all you can leverage existence of closures in C# so you will not need to provide a parameter:
private async Task<Out> MakeAIFCall<Out>(Func<Task<Out>> call)
{
Out #out;
try
{
#out = await call();
}
....
}
And use it like that:
await MakeAIFCall(() => aifClient.getKeysAsync(getKeysRequest));

In app billing plugin fails on Xamarin.Android with a vague error message ("Something went wrong on our end. Please try again")

When using James Montemagno's In App Billing Plugin for Xamarin.Android, a vague error message appears at the purchase screen when attempting to purchase products from Google Play:
Something went wrong on our end. Please try again
I am more or less completely using sample code from the plugin's documentation. The plugin works fine with reserved billing IDs for testing, such as android.test.purchased. This support forum states that the issue is due to "existing security measures", which is not particularly clear- https://forums.xamarin.com/discussion/153166/in-app-purchase-error-something-went-wrong-on-our-end-please-try-again.
The error code that results is Plugin.InAppBilling.Abstractions.PurchaseError.UserCancelled.
Here is the code for the purchasing function:
class ProVersionUnlocker
{
string ProductID = "XXXXXXXXXXXX";
public async Task<bool> WasProVersionPurchased()
{
/*TESTING
*
* TESTING
*
* TESTING
*/
#if DEBUG
//return true;
#endif
var billing = CrossInAppBilling.Current;
try
{
var connected = await billing.ConnectAsync(ItemType.InAppPurchase);
if (!connected)
{
//Couldn't connect
return false;
}
//check purchases
var purchases = await billing.GetPurchasesAsync(ItemType.InAppPurchase);
//check for null just incase
if (purchases?.Any(p => p.ProductId == ProductID) ?? false)
{
//Purchase restored
return true;
}
else
{
//no purchases found
return false;
}
}
catch (InAppBillingPurchaseException purchaseEx)
{
//Billing Exception handle this based on the type
Log.Debug("IAP", "Error: " + purchaseEx);
}
catch (Exception ex)
{
//Something has gone wrong
}
finally
{
await billing.DisconnectAsync();
}
return false;
}
public async Task<bool> PurchaseProVersion()
{
if (await WasProVersionPurchased())
return true;
string Payload = "ProVersionProVersion";
var billing = CrossInAppBilling.Current;
try
{
var connected = await billing.ConnectAsync(ItemType.InAppPurchase);
if (!connected)
{
//we are offline or can't connect, don't try to purchase
return false;
}
//check purchases
var purchase = await billing.PurchaseAsync(ProductID, ItemType.InAppPurchase, Payload, new Verify());
//Consume for further testing
//var consumedItem = await CrossInAppBilling.Current.ConsumePurchaseAsync(purchase.ProductId, purchase.PurchaseToken);
//possibility that a null came through.
if (purchase == null)
{
//did not purchase; do nothing and fall through to failure
}
else if (purchase.State == PurchaseState.Purchased)
{
return true;
}
}
catch (InAppBillingPurchaseException purchaseEx)
{
//Billing Exception handle this based on the type
//Maybe it was an Already Purchased Error, in which case we return true
if (purchaseEx.PurchaseError == PurchaseError.AlreadyOwned)
return true;
Log.Debug("IAP", "Error: " + purchaseEx);
}
catch (Exception ex)
{
//Something else has gone wrong, log it
Log.Debug("IAP", "Issue connecting: " + ex);
}
finally
{
await billing.DisconnectAsync();
}
return false;
}
public class Verify : IInAppBillingVerifyPurchase
{
const string key1 = #"XOR_key1";
const string key2 = #"XOR_key2";
const string key3 = #"XOR_key3";
public Task<bool> VerifyPurchase(string signedData, string signature, string productId = null, string transactionId = null)
{
//This is only used for testing things at the moment.
#if false
var key1Transform = Plugin.InAppBilling.InAppBillingImplementation.InAppBillingSecurity.TransformString(key1, 1);
var key2Transform = Plugin.InAppBilling.InAppBillingImplementation.InAppBillingSecurity.TransformString(key2, 2);
var key3Transform = Plugin.InAppBilling.InAppBillingImplementation.InAppBillingSecurity.TransformString(key3, 3);
return Task.FromResult(Plugin.InAppBilling.InAppBillingImplementation.InAppBillingSecurity.VerifyPurchase(key1Transform + key2Transform + key3Transform, signedData, signature));
#else
return Task.FromResult(true);
#endif
}
}
Here is the calling code, which is within a PreferenceFragment:
var Unlocker = new ProVersionUnlocker();
var unlock = this.FindPreference("unlock");
unlock.PreferenceClick += async (sender, e) =>
{
//Toast.MakeText(Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity, "Ayy lmao", ToastLength.Short).Show();
unlock.SetSummary(Resource.String.PressAgain);
bool Success = await Unlocker.PurchaseProVersion();
//Toast.MakeText(Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity, Success.ToString(), ToastLength.Short).Show();
UnlockStuff();
};

Site not working Error if the function is not working

I have a function which checks and authenticates the User and on that basis the data is displayed to the respective User. And the function name is Get_AuthenticateUser_Ums(strUserName);
I call this function on Page_load. This function contains a web service. Now what I want is whenever the service is not working or has some issue, I want that the site should not be displayed to the user and message should prompt as The service is down, so couldnt load the site.
Below is my code
if (!IsPostBack)
{
Get_AuthenticateUser_Ums(strUserName); }
And function
private void Get_AuthenticateUser_Ums(string strUserName)
{
try
{
strReturnMessage = string.Empty;
Boolean bolReturn = ObjUMS.AuthenticateApplicationAccess(strUserName, strAppUrl, out strReturnMessage);
if (bolReturn)
{
DataSet dsUserGroups = new DataSet();
dsUserGroups = ObjUMS.GetUserAppDetailsbyUserNameApplicationUrl(strUserName, strAppUrl, out strReturnMessage);
if (dsUserGroups.Tables[1] != null && dsUserGroups.Tables[1].Rows.Count > 0)
{
string strSubGroupName = dsUserGroups.Tables[1].Rows[0]["SUBGROUP_NAME"].ToString();
if (strSubGroupName == "UBR Requester")
{
if (dsUserGroups.Tables[2] != null && dsUserGroups.Tables[2].Rows.Count > 0)
{
string[] allStates = dsUserGroups.Tables[2].AsEnumerable().Select(r => r.Field<string>("BOUNDARY_VALUE")).ToArray();
ViewState["States"] = string.Join(",", allStates);
}
}
else
{
Response.Redirect("~/NotAuthorize.aspx", false);
}
}
else
{
Response.Redirect("~/NotAuthorize.aspx", false);
}
}
else
{
Response.Redirect("~/NotAuthorize.aspx", false);
}
}
catch (Exception ex)
{
throw ex;
}
}
you can create a Method to check connection using the url to svc , and which returns a boolean based on that you can able to see whether the Service is up or not
public bool checkConnection(){
var url = "http://nvmbd1bkh150v02/UMSService/UserProvider.svc";
bool tosend = false;
try
{
var myRequest = (HttpWebRequest)WebRequest.Create(url);
var response = (HttpWebResponse)myRequest.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
tosend = true ;
// it's at least in some way responsive
// but may be internally broken
// as you could find out if you called one of the methods for real
Debug.Write(string.Format("{0} Available", url));
}
else
{
tosend = false;
// well, at least it returned...
Debug.Write(string.Format("{0} Returned, but with status: {1}",
url, response.StatusDescription));
}
}
catch (Exception ex)
{
// not available at all, for some reason
Debug.Write(string.Format("{0} unavailable: {1}", url, ex.Message));
}
return tosend;
}

How can I use User Agent to detect request is Coming from desktop or mobile?

Here Is My method where I am getting userdetails who logging my application.I want to check the request is coming from desktop or mobile,using User agent.How can I do this?
public UserDetails Authenticate()
{
try
{
_logger.Info("authenticating...");
var message = OperationContext.Current.RequestContext.RequestMessage;
var request = (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name];
string token = request.Headers[HttpRequestHeader.Authorization];
var base64decodedtoken = this.Base64Decode(token);
UserBLL user = new UserBLL();
var userdetails = user.GetUserDetails(base64decodedtoken, true);
if (userdetails.UserId > 0)
{
_logger.Info("authentication successfull... for user id" + userdetails.UserId);
int i = user.AuditUserLogin(userdetails.Email);
}
else
{
_logger.Info("Unauthorised Access" + userdetails.Email);
}
return userdetails;
}
catch (Exception ex)
{
_logger.Error("Error Occured in Authentication Service", ex);
ErrorData errorData = new ErrorData("Error Occured ", ex.Message);
throw new WebFaultException<ErrorData>(errorData, HttpStatusCode.Unauthorized);
}
}
Please refer to this MDN article for your answer.
Basically, the mobile/desktop detection by user-agent is not suggested, but if you have to get your work sorted in this way, you can also refer to this link

How do I trap Cancelling of a long-running deferred DTF Custom Action?

I've got a Deferred Custom Action DLL written in DTF that publishes a set of .RDL files to the SQL Server Reporting Web Service. All is working well and I can trap most of the error conditions in various Try Catch blocks.
The only thing I am having trouble with is if the user presses the Cancel button in the installer while the publish is happening. It does immediately pop up a message asking if I want to Cancel the install, but if I answer Yes then it throws a message :
Exception of type Microsoft.Deployment.WindowsInstaller.InstallCanceledException was thrown
and just an OK button.
I've tried adding a special Exception handler of
catch (InstallCanceledException ex)
{
}
prior to other exceptions, but it just doesn't seem to capture this one particular exception.
Any suggestions how to handle the InstallCanceledException during a Cancel of a long-running Deferred Custom Action?
The product team looked at using one of the applications but normal users run the applications and they wouldn't necessarily know the web service URL or have permissions to publish the reports to the web service. The installer I have put this in is usually used for running SQL Scripts and I'm adding a second Feature to the installer to Publish the reports. It's actually working too well to abandon it now. Product has seen what I've done already and they love it. The MSI Progress Bar is updating with the name of each report as they are published. The MSI prompts for the URI and user credentials and it already knows what folder the .RDL files are in. I run a Validation on the URI when they click the next button so by the time I run the Deferred action in the Execution Sequence it has a good URI and credentials. I've even gone so far as while the publish is occurring I disconnect from VPN and it fails with a proper error. It is literally only when the user presses Cancel that I can't seem to trap that one, but it is also not a showstopper for this work to go out.
Hiding the Cancel button is not an appropriate option since it is fine if they Cancel at any time.
public static ActionResult PublishSSRSReports(Session session)
{
session.Log("Begin PublishSSRSReports");
bool bFolderExists = false;
string sCustomActionData;
sCustomActionData = session["CustomActionData"];
string INSTALLDIR = Convert.ToString(MsiGetCustomActionDataAttribute(sCustomActionData, "/InstallDir="));
string SSRSURL = Convert.ToString(MsiGetCustomActionDataAttribute(sCustomActionData, "/SsrsUrl="));
string USERCREDENTIALS = Convert.ToString(MsiGetCustomActionDataAttribute(sCustomActionData, "/Credentials="));
string USERNAME = Convert.ToString(MsiGetCustomActionDataAttribute(sCustomActionData, "/Username="));
string PASSWORD = Convert.ToString(MsiGetCustomActionDataAttribute(sCustomActionData, "/Password="));
string ReportsFolderPath = INSTALLDIR + "SSRSReports";
DirectoryInfo directory = new DirectoryInfo(ReportsFolderPath);
FileInfo[] reports = directory.GetFiles("*.rdl"); //Getting all RDL files
ResetProgressBar(session, reports.Length);
CatalogItem[] catalogitem = null;
using (ReportingService2010 rsc = new ReportingService2010())
{
rsc.Url = SSRSURL;
if (USERCREDENTIALS == "0")
{
rsc.Credentials = System.Net.CredentialCache.DefaultCredentials; //User credential for Reporting Service
//the current logged system user
}
if (USERCREDENTIALS == "1")
{
string[] userdomain = USERNAME.Split(Convert.ToChar("\\"));
rsc.Credentials = new System.Net.NetworkCredential(userdomain[1], PASSWORD, userdomain[0]);
}
catalogitem = rsc.ListChildren(#"/", false);
foreach (CatalogItem catalog in catalogitem)
{
if (catalog.Name == (DP))
{
EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, DP + " folder already exists");
bFolderExists = true;
}
}
if (bFolderExists == false)
{
rsc.CreateFolder(DP, #"/", null);
}
Warning[] Warnings = null;
foreach (FileInfo ReportFile in reports)
{
Byte[] definition = null;
Warning[] warnings = null;
try
{
FileStream stream = ReportFile.OpenRead();
definition = new Byte[stream.Length];
stream.Read(definition, 0, (int)stream.Length);
stream.Close();
}
catch (InstallCanceledException ex)
{
//session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Message);
return ActionResult.UserExit;
}
catch (IOException ex)
{
session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Message);
return ActionResult.Failure;
}
catch (Exception ex)
{
session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Message);
return ActionResult.Failure;
}
try
{
CatalogItem report = rsc.CreateCatalogItem("Report", ReportFile.Name, #"/" + DP, true, definition, null, out Warnings);
DisplayActionData(session, ReportFile.Name);
IncrementProgressBar(session, 1);
if (report != null)
{
EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ReportFile.Name + " Published Successfully ");
}
if (warnings != null)
{
foreach (Warning warning in warnings)
{
EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, string.Format("Report: {0} has warnings", warning.Message));
}
}
else
{
EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, string.Format("Report: {0} created successfully with no warnings", ReportFile.Name));
}
}
catch (InstallCanceledException ex)
{
//session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Message);
return ActionResult.UserExit;
}
catch (SoapException ex)
{
session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Detail.InnerXml.ToString());
return ActionResult.Failure;
}
catch (Exception ex)
{
session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Message);
return ActionResult.Failure;
}
}
}
return ActionResult.Success;
I've also got these in the class
private const string SpaceForwardSlash = " /";
private const string DP = "Test";
In the DTF source code the only place I see an InstallCanceledException being thrown is in Session.Message(). This is a wrapper for the MsiProcessMessage Windows API function. It looks to me like you would get this exception if you used Session.Message() to display a message box from a managed custom action, and then clicked the 'Cancel' button. DTF sees the message box 'cancel' return code and throws an InstallCanceledException. Perhaps it's then falling into a catch block somewhere (could be a different action?) where you call something similar to
session.Message(InstallMessage.Error, new Record { FormatString = ex.Message })
which displays the second message box containing just the exception.
I can't quite piece everything together 100% without seeing your MSI source or a complete log file, but maybe this will help.
Here's how Session.Message() is defined in the DTF source:
public MessageResult Message(InstallMessage messageType, Record record)
{
if (record == null)
{
throw new ArgumentNullException("record");
}
int ret = RemotableNativeMethods.MsiProcessMessage((int) this.Handle, (uint) messageType, (int) record.Handle);
if (ret < 0)
{
throw new InstallerException();
}
else if (ret == (int) MessageResult.Cancel)
{
throw new InstallCanceledException();
}
return (MessageResult) ret;
}

Categories