In an ASP.NET application typical error handling code involves some variation of GetLastError(), however there's also HttpContext.AllErrors collection of which the GetLastError() method only retrieves the first one. What are the scenarios where the AllErrors collection might contain more than 1 exception? I cannot think of anything, but obviously it's there for a purpose...
The ASP.NET Framework supports a different model where a request can encounter multiple errors, all of which can be reported without stopping request processing, allowing for more nuanced and useful information to be presented to the user.
namespace ErrorHandling
{
// sample class adding errors to HttpContext
public partial class SumControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
int? first = GetIntValue("first");
int? second = GetIntValue("second");
if (first.HasValue && second.HasValue)
{
//result.InnerText = (first.Value + second.Value).ToString();
//resultPlaceholder.Visible = true;
}
else
{
Context.AddError(new Exception("Cannot perform calculation"));
}
}
}
private int? GetIntValue(string name)
{
int value;
if (Request[name] == null)
{
Context.AddError(new ArgumentNullException(name));
return null;
}
else if (!int.TryParse(Request[name], out value))
{
Context.AddError(new ArgumentOutOfRangeException(name));
return null;
}
return value;
}
}
}
// intercepting the errors
public class Global : System.Web.HttpApplication
{
protected void Application_EndRequest(object sender, EventArgs e)
{
if (Context.AllErrors != null && Context.AllErrors.Length > 1)
{
Response.ClearHeaders();
Response.ClearContent();
Response.StatusCode = 200;
Server.Execute("/MultipleErrors.aspx");
Context.ClearError();
}
}
}
// MultipleErrors code behind
public partial class MultipleErrors : System.Web.UI.Page
{
public IEnumerable<string> GetErrorMessages()
{
return Context.AllErrors.Select(e => e.Message);
}
}
The answer is heavily referencing pro asp.net 4.5 from appress
Related
I am doing a quiz game in Xaramin. forms. and for the score function. if the user got a correct answer, I want the score will add 1.but in my case even the give the correct answer, the score is not adding.
I am also trying to bind to the "score" variable to a label. I want to know if i put a correct code or not.
Button
private void submit_Clicked(object sender, EventArgs e)
{
string answer = this.answer.Text;
string canswer = "correct";
if (answer != null)
{
string ranswer = answer.Replace(" ", string.Empty);
if (ranswer.ToLower() == canswer)
{
DisplayAlert("GoodJob", "You got the correct answer", "OK");
bindingModel b = new bindingModel();
b.score++;
(sender as Button).IsEnabled = false;
}
else
{
DisplayAlert("Unfortunately", "Your answer is wrong", "OK");
(sender as Button).IsEnabled = false;
}
}
}
ViewModel
public class bindingModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int displayScore => Score;
public int score = 0;
void OnPropertyChanged(int score)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(score.ToString()));
}
public int Score
{
get => score;
set
{
if (score != value)
{
score = value;
OnPropertyChanged(score);
}
}
}
}
Model
<Label Text="{Binding Score}"/>
in your page constructor, keep a reference to your VM
bindingModel VM;
// this is your constructor, the name will match your page name
public MyPage()
{
InitializeComponent();
this.BindingContext = VM = new bindingModel();
...
}
then in your event handler, you do NOT need to create a new bindingModel
// update the Count on the VM
VM.Count++;
Answer
There's two things broken here:
You are re-initializing your ViewModel instead of referencing the same instance
You are passing the wrong value into PropertyChangedEventArgs
1. Referencing the View Model
You are re-initializing the ViewModel every time by calling bindingModel b = new bindingModel();
Lets initialize the ViewModel once, store it as a field, set it as the BindingContext for our ContentPage, and reference that field in submit_Clicked
public partial class QuizPage : ContentPage
{
readonly bindingModel _bindingModel;
public QuizPage()
{
_bindingModel = new bindingModel();
BindingContext = _bindingModel;
}
private async void submit_Clicked(object sender, EventArgs e)
{
string answer = this.answer.Text;
string canswer = "correct";
Button button = (Button)sender;
if (answer != null)
{
string ranswer = answer.Replace(" ", string.Empty);
if (ranswer.ToLower() == canswer)
{
await DisplayAlert("GoodJob", "You got the correct answer", "OK");
_bindingModel.score++;
button.IsEnabled = false;
}
else
{
await DisplayAlert("Unfortunately", "Your answer is wrong", "OK");
button.IsEnabled = false;
}
}
}
}
2. PropertyChangedEventArgs
You need to pass in the name of the property to PropertyChangedEventArgs.
They way PropertyChanged works is that it announces the name of the property that has changed. In this case, it needs to broadcast that the Score property has changed.
Let's use nameof(Score) to pass in the string "Score" to PropertyChangedEventArgs:
void OnScorePropertyChanged()
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(displayScore)));
}
public int Score
{
get => score;
set
{
if (score != value)
{
score = value;
OnScorePropertyChanged();
}
}
}
I'd like to wrap all the controller methods using Spring AOP for Error Handling.
But, How to send e.getMessage() in catch block to ${errorMessage} in error.html properly?
Thanks for the response!
#Pointcut("within(com.test.mvc.controller.*) && #within(org.springframework.stereotype.Controller)")
public void controllerLayer() {
}
#Pointcut("execution(public String *(..))")
public void publicMethod() {
}
#Pointcut("controllerLayer() && publicMethod()")
public void controllerPublicMethod() {
}
#Around("controllerPublicMethod()")
public String processRequest(ProceedingJoinPoint joinPoint) {
try {
return (String) joinPoint.proceed();
} catch (Throwable e) {
LOGGER.info("{}", e.getMessage());
return "error.html";
}
}
<body>
<h1>Something went wrong!</h1>
<h3 th:text="'Error Message: ' + ${errorMessage}"></h3>
</body>
Following aspect can set the request attribute to display errorMessage.
#Around("controllerPublicMethod()")
public Object processRequest(ProceedingJoinPoint joinPoint) {
Object object=null;
try {
object = joinPoint.proceed();
} catch (Throwable e) {
RequestContextHolder.getRequestAttributes().setAttribute("errorMessage",e.getMessage(),0); // scope 0 - request , 1 - session
return "error.html";
}
return object;
}
I recommend you please explore the possibilities of #ControllerAdvice
I have a custom BizTalk 2013 R2 pipeline component that has several design-time properties defined. For some reason, BizTalk will load the design-time property values set in the VS pipeline designer but it ignores run-time values set in the BizTalk Admin Console. My component implements IPersistPropertyBag and I have verified that it is not throwing any exceptions.
While debugging the pipeline (attached to Isolated Host Instance), I noticed that BizTalk is only calling the Load method when the pipeline is instantiated. This only loads the VS designer values and BizTalk is supposed to then call the Load method again before calling Execute. Unfortunately, this is not happening.
[Edit] I did some more debugging and figured out that this only seems to be happening on the send pipeline for a two-way receive port. The receive pipeline loads both the design-time and run-time properties as expected.
Here is a sample of my code:
[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[ComponentCategory(CategoryTypes.CATID_Encoder)]
[System.Runtime.InteropServices.Guid(COMPONENT_GUID)]
public class RhapsodyMessageEncoder : BasePipelineComponent, IBaseComponent, IComponentUI,
IPersistPropertyBag, Microsoft.BizTalk.Component.Interop.IComponent
{
...
public void Load(IPropertyBag propertyBag, int errorLog)
{
try
{
this.Enabled = Convert.ToBoolean(this.ReadPropertyBag(propertyBag, "Enabled"));
this.UsernameSSOKey = this.ReadPropertyBag(propertyBag, "UsernameSSOKey") as string;
this.PasswordSsoKey = this.ReadPropertyBag(propertyBag, "PasswordSsoKey") as string;
this.AffiliateAppName = this.ReadPropertyBag(propertyBag, "AffiliateAppName") as string;
}
catch (Exception e) { this.WriteErrorLog(e); }
}
public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
{
try
{
this.WritePropertyBag(propertyBag, "Enabled", this.Enabled);
this.WritePropertyBag(propertyBag, "UsernameSSOKey", this.UsernameSSOKey);
this.WritePropertyBag(propertyBag, "PasswordSsoKey", this.PasswordSsoKey);
this.WritePropertyBag(propertyBag, "AffiliateAppName", this.AffiliateAppName);
}
catch (Exception e) { this.WriteErrorLog(e); }
}
...
}
Read / Write Property bag helper methods:
protected virtual object ReadPropertyBag(IPropertyBag pb, string propName)
{
PropertyInfo pInfo = this.GetType().GetProperty(propName);
object currentValue = null;
object val = null;
if (pInfo != null)
currentValue = pInfo.GetValue(this, null);
try
{
pb.Read(propName, out val, 0);
}
catch (System.ArgumentException e)
{
System.Diagnostics.Trace.WriteLine(
"Argument Exception encountered: " + e.Message,
this.Name
);
}
catch (System.Exception e)
{
throw new System.ApplicationException("Can't read design time Properties", e);
}
return val ?? currentValue;
}
protected virtual void WritePropertyBag(IPropertyBag pb, string propName, object val)
{
try
{
object obj = val;
pb.Write(propName, ref obj);
}
catch (System.Exception e)
{
throw new System.ApplicationException("Can't write design time properties", e);
}
}
I am using Caliburn micro(1.3)/MVVM and Silverlight. When I update the itemsource RadGridView, I lose the selected items. I found a blog about implementing a behavior to save the selected items when you are implementing MVVM. I can get the selected items, but I cannot set them back once the itemsource is refreshed. Can someoneshow me how to implement this using caliburn.micro and the RadGridVIew? I think the best way to go is to create a caliburn micro convention, but I can only find a reference for creating a convention for selectedItem, not selectedItems.
Can someone show me how to accomplish this? I tried the following, but it does not work.
private static void SetRadGridSelecteditemsConventions()
{
ConventionManager
.AddElementConvention<DataControl>(DataControl.ItemsSourceProperty, "SelectedItem", "SelectionChanged")
.ApplyBinding = (viewModelType, path, property, element, convention) =>
{
ConventionManager.SetBinding(viewModelType, path, property, element, convention, DataControl.ItemsSourceProperty);
if (ConventionManager.HasBinding(element, DataControl.SelectedItemProperty))
return true;
var index = path.LastIndexOf('.');
index = index == -1 ? 0 : index + 1;
var baseName = path.Substring(index);
foreach (var selectionPath in
from potentialName in ConventionManager.DerivePotentialSelectionNames(baseName)
where viewModelType.GetProperty(potentialName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) != null
select path.Replace(baseName, potentialName))
{
var binding = new Binding(selectionPath) { Mode = BindingMode.TwoWay };
BindingOperations.SetBinding(element, DataControl.SelectedItemProperty, binding);
}
return true;
};
}
Thanks,
Stephane
You should use a behavior for this since the SelectedItems property is readonly.
Telerik has an example for this, only the example is not specific for caliburn.micro.
If you add the following class to your project:
public class MultiSelectBehavior : Behavior<RadGridView>
{
public INotifyCollectionChanged SelectedItems
{
get { return (INotifyCollectionChanged)GetValue(SelectedItemsProperty); }
set { SetValue(SelectedItemsProperty, value); }
}
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(INotifyCollectionChanged), typeof(MultiSelectBehavior), new PropertyMetadata(OnSelectedItemsPropertyChanged));
private static void OnSelectedItemsPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
var collection = args.NewValue as INotifyCollectionChanged;
if (collection != null)
{
collection.CollectionChanged += ((MultiSelectBehavior)target).ContextSelectedItems_CollectionChanged;
}
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectedItems.CollectionChanged += GridSelectedItems_CollectionChanged;
}
void ContextSelectedItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UnsubscribeFromEvents();
Transfer(SelectedItems as IList, AssociatedObject.SelectedItems);
SubscribeToEvents();
}
void GridSelectedItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
UnsubscribeFromEvents();
Transfer(AssociatedObject.SelectedItems, SelectedItems as IList);
SubscribeToEvents();
}
private void SubscribeToEvents()
{
AssociatedObject.SelectedItems.CollectionChanged += GridSelectedItems_CollectionChanged;
if (SelectedItems != null)
{
SelectedItems.CollectionChanged += ContextSelectedItems_CollectionChanged;
}
}
private void UnsubscribeFromEvents()
{
AssociatedObject.SelectedItems.CollectionChanged -= GridSelectedItems_CollectionChanged;
if (SelectedItems != null)
{
SelectedItems.CollectionChanged -= ContextSelectedItems_CollectionChanged;
}
}
public static void Transfer(IList source, IList target)
{
if (source == null || target == null)
return;
target.Clear();
foreach (var o in source)
{
target.Add(o);
}
}
}
This behavior takes care of the synchronization between collection RadGridView.SelectedItems and MultiSelectBehavior.SelectedItems.
Now we need to have an ObservableCollection in the ViewModel
//Collection holding the selected items
private ObservableCollection<object> selectedGridItems;
public ObservableCollection<object> SelectedGridItems
{
get
{
if (selectedGridItems == null)
selectedGridItems = new ObservableCollection<object>();
return selectedGridItems;
}
set
{
if (selectedGridItems == value) return;
selectedGridItems = value;
NotifyOfPropertyChange(() => SelectedGridItems);
}
}
//Deselect all selected items in the gridview
public void ClearSelectedGridItems()
{
SelectedGridItems.Clear();
}
Last thing is bind the behavior in the view
<telerik:RadGridView x:Name="CustomLogs" AutoGenerateColumns="true" SelectionMode="Extended">
<i:Interaction.Behaviors>
<local:MultiSelectBehavior SelectedItems="{Binding SelectedGridItems}"/>
</i:Interaction.Behaviors>
</telerik:RadGridView>
Thats it, hope it helps you!
I am developing an asp.net (3.5) application and I am puzzled with the behavior of the postbacks.
Consider the following scenario: I have a web user control that is basically a form. However each form field is a web user control in itself.
In the click event of the save button I iterate through all controls in my form and I retrieve the field value and the field name that refers to the database field that I am saving the value to.
The click event triggers a postback and it is during the postback that I visit the controls and here is the funny thing: the property value for the database field has become null! Could anyone shed a light here?
Here is some basic code:
[Serializable]
public partial class UserProfileForm : CustomIntranetWebappUserControl
{
protected override void OnInit(EventArgs e)
{
//AutoEventWireup is set to false
Load += Page_Load;
CancelLinkButton.Click += CancelButtonClickEvent;
SaveLinkButton.Click += SaveButtonClickEvent;
base.OnInit(e);
}
private void SaveButtonClickEvent(object sender, EventArgs e)
{
VisitFormFields();
}
private void VisitFormFields()
{
var userProfileVisitor = new UserProfileVisitor();
foreach (var control in Controls)
{
if (control is FormFieldUserControl)
{
var formField = (FormFieldUserControl) control;
formField.Visit(userProfileVisitor);
}
}
userProfileVisitor.Save();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindText();
}
}
private void BindText()
{
LastNameFormLine.LabelText = string.Format("{0}:", HomePage.Localize("Last Name"));
LastNameFormLine.InputValue = UserProfile.LastName;
LastNameFormLine.IsMandatoryField = true;
LastNameFormLine.IsMultilineField = false;
LastNameFormLine.ProfileField = "UserProfile.LastName";
//... the rest of this method is exactly like the 4 lines above.
}
}
[Serializable]
public abstract class FormFieldUserControl : CustomIntranetWebappUserControl
{
public string ProfileField { get; set; }
public abstract void Visit(UserProfileVisitor userProfileVisitor);
}
[Serializable]
public partial class FormLineTextBox : FormFieldUserControl
{
//... irrelevant code removed...
public override void Visit(UserProfileVisitor userProfileVisitor)
{
if (userProfileVisitor == null)
{
Log.Error("UserProfileVisitor not defined for the field: " + ProfileField);
return;
}
userProfileVisitor.Visit(this);
}
}
[Serializable]
public class UserProfileVisitor
{
public void Visit(FormLineTextBox formLine)
{
// The value of formLine.ProfileField is null!!!
Log.Debug(string.Format("Saving form field type {1} with profile field [{0}] and value {2}", formLine.ProfileField, formLine.GetType().Name, formLine.InputValue));
}
// ... removing irrelevant code...
public void Save()
{
Log.Debug("Triggering the save operation...");
}
}
Remember ASP.NET is stateless. Any properties created are destroyed after the page has been render to the browser. So you have to recreate objects on each post back or store them in View, Session, or Application State.
When you do a property you have to tell it to save the view state it does not do it automatically. Here is a sample of a view state property.
public string SomePropertyAsString
{
get
{
if (this.ViewState["SomePropertyAsString"] == null)
return string.Empty;
return (string)this.ViewState["SomePropertyAsString"];
}
set { this.ViewState["SomePropertyAsString"] = value; }
}
public MyCustomType ObjectProperty
{
get
{
if (this.ViewState["ObjectProperty"] == null)
return null;
return (MyCustomType)this.ViewState["ObjectProperty"];
}
set { this.ViewState["ObjectProperty"] = value; }
}
First guess would be that BindText() shouldn't be in Page_Load, but in Page_Init, so the control state will be saved.
#David Basarab, this is not true afaik, and was only the case in .Net 1.1, in .Net2 and up this is all handled by the framework if you do all the magic stuff in the Init.
Your problem is that 'ProfileField' isn't available on the Postback, right?
The solution is to store the value for that in ViewState (instead of an auto-implemented property). Without that, it won't be available on the postback.