WorkflowItemPresenter contents disappear on build - c#

Ello all,
In my custom activity, when I drop an activity into the WorkflowItemPresenter, save and compile, my activity suddenly disappears and I have no freakin clue why. I'm probably making some noob mistake somewhere but, I'm not seeing it. I've gone back and made sure my code complies fine and deleted and re-added my assembly containing the custom activity on the off chance it might just be a fluke. After which when I attempt to compile from the project referencing my custom activity. It runs but throws an ArgumentNullException. I've tried passing it bools, conditionals and just about anthing else it would take all ending with the same result. Any suggestions on troubleshooting ideas to try in this case or obvious stuff missing?
Here is my reference to my condition ActivityFunc <bool> Condition.
<sap:WorkflowItemPresenter
HintText="Add Trigger conditional activities here"
Item="{Binding Path=ModelItem.Condition.Handler}"
Height="40"
/>
Here is my reference to the child I want to schedule after the condition returns true public ActivityAction Child.
<sap:WorkflowItemPresenter
HintText="Add activies that happen on trigger firing"
Item="{Binding Path=ModelItem.Child.Handler}"
Height="40"/>
Here is my Custom activity
[Designer(typeof(TriggerDesigner)),
Description("Creates a Trigger for use by trigger conditionals"), ToolboxCategory(ToolboxCategoryAttribute.Trigger),
ToolboxBitmap(typeof(Shaolin.Activities.ToolboxIconAttribute), "ToolboxIcons.CreateImportContext")]
public sealed class Trigger : NativeActivity
{
/// <summary>
/// The initial Condition that determines if the trigger should be scheduled
/// </summary>
/// <value>The condition.</value>
public ActivityFunc<bool> Condition { get; set; }
/// <summary>
/// The resulting action that is scheduled if the Condition is true
/// </summary>
/// <value>The child.</value>
public ActivityAction Child { get; set; }
/// <summary>
/// Gets or sets the value holding whether or not the trigger matches the condition
/// </summary>
/// <value>The type of the match.</value>
public MatchType MatchType{ get; set; }
/// <summary>
/// Perform evaluation of Condition; if is true then schedules Child
/// </summary>
/// <param name="context">The execution context in which the activity executes.</param>
protected override void Execute(NativeActivityContext context)
{
context.ScheduleFunc<bool>(this.Condition, new CompletionCallback<bool>(OnConditionComplete));
}
/// <summary>
/// Called from Execute when Condition evaluates to true.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="instance">The instance.</param>
/// <param name="result">if set to <c>true</c> [result].</param>
public void OnConditionComplete(NativeActivityContext context, ActivityInstance instance, bool result)
{
//check if Condition evaluation returns true
if (result)
{
//If so then schedule child Activity
context.ScheduleAction(Child);
}
}
}
}

Hello person with the same IP as me.
ModelItem.Condition is null. Your binding fails, therefore, but with little fanfare which makes this situation hard to figure out.
You need to implement IActivityTemplateFactory and configure your activity in the Create method:
Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
{
return new Trigger
{
DisplayName = "lol trigger",
Condition = new ActivityFunc<bool>(),
Child = new ActivityAction(),
MatchType = MatchType.Lol
};
}

Related

How do I get intellisense for record properties?

Given this code:
/// <summary>
/// When identity verification has occurred.
/// </summary>
/// <param name="ConsumerId">The id of the consumer</param>
public record IdentityVerificationDecidedEvent(String ConsumerId)
{
}
I thought adding param name would do it, but it only does it on the ctor of the record object. How do I decorate the
String ConsumerId
to get the intellisense comment for
myEvent.ConsumerId
to appear?

WPF MVVM Communication with Messenger (post-message load of VM)

Background
I am writing a WPF application using the MVVM pattern. I am using a Messenger to communicate between ViewModels as I learned in various tutorials. I am using the implementation of a Messenger class found in the Code section of this post (thanks to #Dalstroem WPF MVVM communication between View Model and Gill Cleeren at Pluralsight).
Due to the large number of Views/VMs needed by my app, each ViewModel is instantiated at the time a View is required and disposed subsequently (view-first, VM specified as DataContext of View).
Issue
The constructor of each ViewModel loads resources (Commands, Services, etc.) as necessary, and registers for messages of interest. Messages that were sent from a previously existing ViewModels are not picked up by new ViewModels.
Thus, I cannot communicate between ViewModels using my Messenger class.
Thoughts
Some examples I've seen use a ViewModelLocator that instantiates all ViewModels upfront. The Views, when created, simply pull the existing ViewModel from the VML. This approach means that Messages will always be received and available in every ViewModel. My concern is that with 30+ ViewModels that all load a substantial amount of data with use, my app will become slow with extended use as each View is used (no resources ever disposed).
I've considered finding a way to store Messages and subsequently resend all messages to any registered recipients. If implemented, this would allow me to call a Resend method of sorts after registering for messages in each ViewModel. I have a few concerns with this approach, including the accumulation of messages over time.
I'm not sure what I'm doing wrong or if there are approachs I just don't know about.
Code
public class Messenger
{
private static readonly object CreationLock = new object();
private static readonly ConcurrentDictionary<MessengerKey, object> Dictionary = new ConcurrentDictionary<MessengerKey, object>();
#region Default property
private static Messenger _instance;
/// <summary>
/// Gets the single instance of the Messenger.
/// </summary>
public static Messenger Default
{
get
{
if (_instance == null)
{
lock (CreationLock)
{
if (_instance == null)
{
_instance = new Messenger();
}
}
}
return _instance;
}
}
#endregion
/// <summary>
/// Initializes a new instance of the Messenger class.
/// </summary>
private Messenger()
{
}
/// <summary>
/// Registers a recipient for a type of message T. The action parameter will be executed
/// when a corresponding message is sent.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="recipient"></param>
/// <param name="action"></param>
public void Register<T>(object recipient, Action<T> action)
{
Register(recipient, action, null);
}
/// <summary>
/// Registers a recipient for a type of message T and a matching context. The action parameter will be executed
/// when a corresponding message is sent.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="recipient"></param>
/// <param name="action"></param>
/// <param name="context"></param>
public void Register<T>(object recipient, Action<T> action, object context)
{
var key = new MessengerKey(recipient, context);
Dictionary.TryAdd(key, action);
}
/// <summary>
/// Unregisters a messenger recipient completely. After this method is executed, the recipient will
/// no longer receive any messages.
/// </summary>
/// <param name="recipient"></param>
public void Unregister(object recipient)
{
Unregister(recipient, null);
}
/// <summary>
/// Unregisters a messenger recipient with a matching context completely. After this method is executed, the recipient will
/// no longer receive any messages.
/// </summary>
/// <param name="recipient"></param>
/// <param name="context"></param>
public void Unregister(object recipient, object context)
{
object action;
var key = new MessengerKey(recipient, context);
Dictionary.TryRemove(key, out action);
}
/// <summary>
/// Sends a message to registered recipients. The message will reach all recipients that are
/// registered for this message type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="message"></param>
public void Send<T>(T message)
{
Send(message, null);
}
/// <summary>
/// Sends a message to registered recipients. The message will reach all recipients that are
/// registered for this message type and matching context.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="message"></param>
/// <param name="context"></param>
public void Send<T>(T message, object context)
{
IEnumerable<KeyValuePair<MessengerKey, object>> result;
if (context == null)
{
// Get all recipients where the context is null.
result = from r in Dictionary where r.Key.Context == null select r;
}
else
{
// Get all recipients where the context is matching.
result = from r in Dictionary where r.Key.Context != null && r.Key.Context.Equals(context) select r;
}
foreach (var action in result.Select(x => x.Value).OfType<Action<T>>())
{
// Send the message to all recipients.
action(message);
}
}
protected class MessengerKey
{
public object Recipient { get; private set; }
public object Context { get; private set; }
/// <summary>
/// Initializes a new instance of the MessengerKey class.
/// </summary>
/// <param name="recipient"></param>
/// <param name="context"></param>
public MessengerKey(object recipient, object context)
{
Recipient = recipient;
Context = context;
}
/// <summary>
/// Determines whether the specified MessengerKey is equal to the current MessengerKey.
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
protected bool Equals(MessengerKey other)
{
return Equals(Recipient, other.Recipient) && Equals(Context, other.Context);
}
/// <summary>
/// Determines whether the specified MessengerKey is equal to the current MessengerKey.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((MessengerKey)obj);
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
unchecked
{
return ((Recipient != null ? Recipient.GetHashCode() : 0) * 397) ^ (Context != null ? Context.GetHashCode() : 0);
}
}
}
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Update
The way my application is architectured, there is a ViewModel used with my MainWindow, which serves as a sort of basic shell. It provides a primary layout with a few controls for navigation and login/logout, etc.
All subsequent Views are displayed inside a ContentControl inside the MainWindow (taking up most of the window real estate). The ContentControl is bound to a "CurrentView" property of my "MainWindowViewModel." The MainWindowViewModel instantiates a custom Navigation service I created for the purpose of selecting and returning the appropriate View to update my "CurrentView" property.
This architecture may be unorthodox, but I wasn't sure how navigation is typically accompished without using out-the-box things like TabControl.
Idea
Building on ideas from #axlj, I could keep an ApplicationState object as a property of my "MainWindowViewModel." Using my Messenger class, I could pub an ApplicationState message whenever injecting a new View in my MainWindow. The ViewModels for each View would, of course, sub this message and gain state immediately upon creation. If any ViewModels make changes to their copy of ApplicationState, they would pub a message. The MainWindowViewModel would then be updated via its subscription.
I would recommend against "storing messages" -- even if you work out a good pattern for recovering messages, you'll still end up with logic that is difficult to test. This is really a sign that your view models need to know too much about the application state.
In the case of view model locator -- a well designed view model locator will likely lazy-load the view models, which would leave you in the same place you are right now.
Option 1
Instead, consider using UserControls and DependencyProperties where possible.
Option 2
If your views are in fact really views, then consider a singleton context class that maintains the necessary state and inject that into your view models. The benefit of this method is that your context class can implement INotifyPropertyChanged and any changes will automatically be propagated to your consuming views.
Option 3
If you're navigating between views, you may want to implement a Navigation service similar to something described here.
interface INavigationService(string location, object parameter) {}
In this case, your parameter is considered your state object. The new view model receives the model data from the view you're navigating away from.
This blog post is helpful in explaining best practices around when to use view models and user controls.
...and registers for messages of interest. Messages that were sent from a previously existing ViewModels are not picked up by new ViewModels. Thus, I cannot communicate between ViewModels using my Messenger class.
Why exactly do your VMs need to be aware of historical messages?
Generally messaging should be pub/sub; messages are published ("pub") and anyone who might be interested in specific messages subscribes ("sub") to receive those. The publisher shouldn't care what is done with the message - that is up to the subscriber.
If you have some obscure business case that requires knowledge of previous messages then you should create your own message queue mechanism (i.e. store them in a database and retrieve them based on datetime).

Unable to cast object of type Page to type 'Windows.UI.Xaml.Controls.Frame' when using mvvm-light navigation service in a win 10 universal app

I m hitting the following error on my new windows 10 universal app C#/XAML:
An exception of type 'System.InvalidCastException' occurred in GalaSoft.MvvmLight.Platform.dll but was not handled in user code
Additional information: Unable to cast object of type '' to type 'Windows.UI.Xaml.Controls.Frame'.
on the following navigating command in one of my page's view model:
_navigationService.NavigateTo(ViewModelLocator.MedicineBoxPageKey);
I am trying to have a hamburger menu style navigation (see this sample). app by Microsoft on an example of how to do this) to:
1- have a convenient solution shared across all my pages. The sample mentioned above uses an AppShell Page as the root of the app instead of a Frame, that encapsulates the navigation menu and some behavior of the back button. That would be ideal.
2- Use the MVVM-Light navigation service to handle all the navigation from my view model conveniently.
Here is how the App.xml.Cs initializes the shell page onLaunched:
AppShell shell = Window.Current.Content as AppShell;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (shell == null)
{
// Create a a AppShell to act as the navigation context and navigate to the first page
shell = new AppShell();
// Set the default language
shell.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
shell.AppFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
}
// Place our app shell in the current Window
Window.Current.Content = shell;
if (shell.AppFrame.Content == null)
{
// When the navigation stack isn't restored, navigate to the first page
// suppressing the initial entrance animation.
shell.AppFrame.Navigate(typeof(MedicinesStorePage), e.Arguments, new Windows.UI.Xaml.Media.Animation.SuppressNavigationTransitionInfo());
}
// Ensure the current window is active
Window.Current.Activate();
And here is the AppShell class definition:
public sealed partial class AppShell : Page
{
public static AppShell Current = null;
public AppShell()
{
this.InitializeComponent();
}
}
From what I have tried so far, the mvvm-light navigation service only works when a Frame is used a root of the app and note a Page (otherwise we get this casting bug).
However using a Frame does not seem to be a option either since as the sample app puts it:
Using a Page as the root for the app provides a design time experience as well as ensures that
when it runs on Mobile the app content won't appear under the system's StatusBar which is visible
by default with a transparent background. It will also take into account the presence of software
navigation buttons if they appear on a device. An app can opt-out by switching to UseCoreWindow.
I also tried to overide the navigationTo method from the mvvm-light navigation service but the bug seems to occur before I could catch it.
Does anyone has a solution to use the mvvm-light navigation service and a shell page as the app root (that manages the hamburger menu, etc.)?
Thanks a lot!
I talked to Laurent Bugnion and he recommended me to implemented my own navigation service who handles the navigation. For this I made a PageNavigationService who implements the INavigationService Interface of MVVM Light.
public class PageNavigationService : INavigationService
{
/// <summary>
/// The key that is returned by the <see cref="CurrentPageKey" /> property
/// when the current Page is the root page.
/// </summary>
public const string RootPageKey = "-- ROOT --";
/// <summary>
/// The key that is returned by the <see cref="CurrentPageKey" /> property
/// when the current Page is not found.
/// This can be the case when the navigation wasn't managed by this NavigationService,
/// for example when it is directly triggered in the code behind, and the
/// NavigationService was not configured for this page type.
/// </summary>
public const string UnknownPageKey = "-- UNKNOWN --";
private readonly Dictionary<string, Type> _pagesByKey = new Dictionary<string, Type>();
/// <summary>
/// The key corresponding to the currently displayed page.
/// </summary>
public string CurrentPageKey
{
get
{
lock (_pagesByKey)
{
var frame = ((AppShell) Window.Current.Content).AppFrame;
if (frame.BackStackDepth == 0)
{
return RootPageKey;
}
if (frame.Content == null)
{
return UnknownPageKey;
}
var currentType = frame.Content.GetType();
if (_pagesByKey.All(p => p.Value != currentType))
{
return UnknownPageKey;
}
var item = _pagesByKey.FirstOrDefault(
i => i.Value == currentType);
return item.Key;
}
}
}
/// <summary>
/// If possible, discards the current page and displays the previous page
/// on the navigation stack.
/// </summary>
public void GoBack()
{
var frame = ((Frame) Window.Current.Content);
if (frame.CanGoBack)
{
frame.GoBack();
}
}
/// <summary>
/// Displays a new page corresponding to the given key.
/// Make sure to call the <see cref="Configure" />
/// method first.
/// </summary>
/// <param name="pageKey">
/// The key corresponding to the page
/// that should be displayed.
/// </param>
/// <exception cref="ArgumentException">
/// When this method is called for
/// a key that has not been configured earlier.
/// </exception>
public void NavigateTo(string pageKey)
{
NavigateTo(pageKey, null);
}
/// <summary>
/// Displays a new page corresponding to the given key,
/// and passes a parameter to the new page.
/// Make sure to call the <see cref="Configure" />
/// method first.
/// </summary>
/// <param name="pageKey">
/// The key corresponding to the page
/// that should be displayed.
/// </param>
/// <param name="parameter">
/// The parameter that should be passed
/// to the new page.
/// </param>
/// <exception cref="ArgumentException">
/// When this method is called for
/// a key that has not been configured earlier.
/// </exception>
public void NavigateTo(string pageKey, object parameter)
{
lock (_pagesByKey)
{
if (!_pagesByKey.ContainsKey(pageKey))
{
throw new ArgumentException(
string.Format(
"No such page: {0}. Did you forget to call NavigationService.Configure?",
pageKey),
"pageKey");
}
var shell = ((AppShell) Window.Current.Content);
shell.AppFrame.Navigate(_pagesByKey[pageKey], parameter);
}
}
/// <summary>
/// Adds a key/page pair to the navigation service.
/// </summary>
/// <param name="key">
/// The key that will be used later
/// in the <see cref="NavigateTo(string)" /> or <see cref="NavigateTo(string, object)" /> methods.
/// </param>
/// <param name="pageType">The type of the page corresponding to the key.</param>
public void Configure(string key, Type pageType)
{
lock (_pagesByKey)
{
if (_pagesByKey.ContainsKey(key))
{
throw new ArgumentException("This key is already used: " + key);
}
if (_pagesByKey.Any(p => p.Value == pageType))
{
throw new ArgumentException(
"This type is already configured with key " + _pagesByKey.First(p => p.Value == pageType).Key);
}
_pagesByKey.Add(
key,
pageType);
}
}
}
Basicly it's a copy of his implementation. But instead of parsing to a Frame I parse to an AppShell and use the AppFrame Property to navigate.
I put this to my ViewModelLocator. Instead of:
var navigationService = new NavigationService();
I will just use:
var navigationService = new PageNavigationService();
EDIT: I Noticed that there is an excpetion in the NavMenuListView when you use the backkey after you navigated with the new navigationservice since the selected item is null. I fixed it with adjusting the SetSelectedItem Method and adding a nullcheck in the for loop after the cast:
public void SetSelectedItem(ListViewItem item)
{
var index = -1;
if (item != null)
{
index = IndexFromContainer(item);
}
for (var i = 0; i < Items.Count; i++)
{
var lvi = (ListViewItem) ContainerFromIndex(i);
if(lvi == null) continue;
if (i != index)
{
lvi.IsSelected = false;
}
else if (i == index)
{
lvi.IsSelected = true;
}
}
}
But there might be a more elegant solution than this.

property inaccessible due to protection level?

This is the line that the error is showing on:
public IOAuth2ServiceProvider<IElance> ElanceServiceProvider { get; set; }
It's showing the error on the IElance Type on that line, but here's the interface:
public interface IElance : IApiBinding
{
/// <summary>
/// Search all jobs, list jobs associated with an employee or a freelancer, and retrieve information for a specific job.
/// </summary>
IJobOperations JobOperations { get; }
/// <summary>
/// Access all messages, users, messages, and Work View™ data associated with an Elance Workroom.
/// </summary>
IWorkRoomOperations WorkroomOperations { get; }
/// <summary>
/// View all of the information associated with an employee or a freelancer.
/// </summary>
IProfileOperations ProfileOperations { get; }
/// <summary>
/// View detailed information on freelancers, and retrieve a list of all freelancers employed by an employer.
/// </summary>
IFreelancerOperations FreelancerOperations { get; }
/// <summary>
/// List Elance groups, and retrieve lists of members and jobs belonging to a group.
/// </summary>
IGroupOperations GroupOperations { get; }
/// <summary>
/// Obtain ancillary Elance information, such as the current list of all job categories.
/// </summary>
IUtilityOperations UtilityOperations { get; }
}
I can't for the life of me figure out why it's telling me this. Am I missing something obvious? I would greatly appreciate any direction on this error.
This is probably caused by IApiBinding or one of its base interfaces not being public. Another possibility is that one of the types used by the interface members is not public.

ASP.net "BasePage" class ideas

What cool functionality and methods do you add to your ASP.net BasePage : System.Web.UI.Page classes?
Examples
Here's something I use for authentication, and I'd like to hear your opinions on this:
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
// Authentication code omitted... Essentially same as below.
if (_RequiresAuthentication && !(IsAuthorized))
{
RespondForbidden("You do not have permissions to view this page.", UnauthorizedRedirect);
return;
}
}
// This function is overridden in each page subclass and fitted to each page's
// own authorization requirements.
// This also allows cascading authorization checks,
// e.g: User has permission to view page? No - base.IsAuthorized - Is user an admin?
protected virtual bool IsAuthorized
{
get { return true; }
}
My BasePage class contains an instance of this class:
public class StatusCodeResponse {
public StatusCodeResponse(HttpContext context) {
this._context = context;
}
/// <summary>
/// Responds with a specified status code, and if specified - transfers to a page.
/// </summary>
private void RespondStatusCode(HttpContext context, System.Net.HttpStatusCode status, string message, string transfer)
{
if (string.IsNullOrEmpty(transfer))
{
throw new HttpException((int)status, message);
}
context.Response.StatusCode = (int)status;
context.Response.StatusDescription = message;
context.Server.Transfer(transfer);
}
public void RespondForbidden(string message, string transfer)
{
RespondStatusCode(this._context, System.Net.HttpStatusCode.Forbidden, message, transfer);
}
// And a few more like these...
}
As a side note, this could be accomplished using extension methods for the HttpResponse object.
And another method I find quite handy for parsing querystring int arguments:
public bool ParseId(string field, out int result)
{
return (int.TryParse(Request.QueryString[field], out result) && result > 0);
}
Session related stuff, some complex object in the BasePage that maps to a session, and expose it as a property.
Doing stuff like filling a crumble pad object.
But most important: do not make your basepage into some helper class. Don't add stuff like ParseId(), that's just ridiculous.
Also, based on the first post: make stuff like IsAuthorized abstract. This way you don't create giant security holes if someone forgets that there is some virtual method.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
namespace MySite
{
/// <summary>
/// Base class with properties for meta tags for content pages
/// http://www.codeproject.com/KB/aspnet/PageTags.aspx
/// http://weblogs.asp.net/scottgu/archive/2005/08/02/421405.aspx
/// </summary>
public partial class BasePage : System.Web.UI.Page
{
private string keywords;
private string description;
/// <SUMMARY>
/// Gets or sets the Meta Keywords tag for the page
/// </SUMMARY>
public string Meta_Keywords
{
get
{
return keywords;
}
set
{
// Strip out any excessive white-space, newlines and linefeeds
keywords = Regex.Replace(value, "\\s+", " ");
}
}
/// <SUMMARY>
/// Gets or sets the Meta Description tag for the page
/// </SUMMARY>
public string Meta_Description
{
get
{
return description;
}
set
{
// Strip out any excessive white-space, newlines and linefeeds
description = Regex.Replace(value, "\\s+", " ");
}
}
// Constructor
// Add an event handler to Init event for the control
// so we can execute code when a server control (page)
// that inherits from this base class is initialized.
public BasePage()
{
Init += new EventHandler(BasePage_Init);
}
// Whenever a page that uses this base class is initialized,
// add meta keywords and descriptions if available
void BasePage_Init(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(Meta_Keywords))
{
HtmlMeta tag = new HtmlMeta();
tag.Name = "keywords";
tag.Content = Meta_Keywords;
Header.Controls.Add(tag);
}
if (!String.IsNullOrEmpty(Meta_Description))
{
HtmlMeta tag = new HtmlMeta();
tag.Name = "description";
tag.Content = Meta_Description;
Header.Controls.Add(tag);
}
}
}
}
Along with the metadata already mentioned (mostly obsolete in ASP.NET 4.0 with the new Page.MetaDescription and Page.MetaKeywords properties), I've also had methods to add other header links to my page such as specific ones for adding page specific CSS, or things like cannonical links, RSS links, etc:
/// <overloads>
/// Adds a CSS link to the page. Useful when you don't have access to the
/// HeadContent ContentPlaceHolder. This method has 4 overloads.
/// </overloads>
/// <summary>
/// Adds a CSS link.
/// </summary>
/// <param name="pathToCss">The path to CSS file.</param>
public void AddCss(string pathToCss) {
AddCss(pathToCss, string.Empty);
}
/// <summary>
/// Adds a CSS link in a specific position.
/// </summary>
/// <param name="pathToCss">The path to CSS.</param>
/// <param name="position">The postion.</param>
public void AddCss(string pathToCss, int? position) {
AddCss(pathToCss, string.Empty, position);
}
/// <summary>
/// Adds a CSS link to the page with a specific media type.
/// </summary>
/// <param name="pathToCss">The path to CSS file.</param>
/// <param name="media">The media type this stylesheet relates to.</param>
public void AddCss(string pathToCss, string media) {
AddHeaderLink(pathToCss, "text/css", "Stylesheet", media, null);
}
/// <summary>
/// Adds a CSS link to the page with a specific media type in a specific
/// position.
/// </summary>
/// <param name="pathToCss">The path to CSS.</param>
/// <param name="media">The media.</param>
/// <param name="position">The postion.</param>
public void AddCss(string pathToCss, string media, int? position) {
AddHeaderLink(pathToCss, "text/css", "Stylesheet", media, position);
}
/// <overloads>
/// Adds a general header link. Useful when you don't have access to the
/// HeadContent ContentPlaceHolder. This method has 3 overloads.
/// </overloads>
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
public void AddHeaderLink(string href, string type) {
AddHeaderLink(href, type, string.Empty, string.Empty, null);
}
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
/// <param name="rel">The relation of the resource to the page.</param>
public void AddHeaderLink(string href, string type, string rel) {
AddHeaderLink(href, type, rel, string.Empty, null);
}
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
/// <param name="rel">The relation of the resource to the page.</param>
/// <param name="media">The media target of the link.</param>
public void AddHeaderLink(string href, string type, string rel, string media)
{
AddHeaderLink(href, type, rel, media, null);
}
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
/// <param name="rel">The relation of the resource to the page.</param>
/// <param name="media">The media target of the link.</param>
/// <param name="position">The postion in the control order - leave as null
/// to append to the end.</param>
public void AddHeaderLink(string href, string type, string rel, string media,
int? position) {
var link = new HtmlLink { Href = href };
if (0 != type.Length) {
link.Attributes.Add(HtmlTextWriterAttribute.Type.ToString().ToLower(),
type);
}
if (0 != rel.Length) {
link.Attributes.Add(HtmlTextWriterAttribute.Rel.ToString().ToLower(),
rel);
}
if (0 != media.Length) {
link.Attributes.Add("media", media);
}
if (null == position || -1 == position) {
Page.Header.Controls.Add(link);
}
else
{
Page.Header.Controls.AddAt((int)position, link);
}
}
Culture initialization by overriding InitializeCulture() method (set culture and ui culture from cookie or DB).
Some of my applications are brandable, then here I do some "branding" stuff too.
I use this methot and thanks for yours,
/// <summary>
/// Displays the alert.
/// </summary>
/// <param name="message">The message to display.</param>
protected virtual void DisplayAlert(string message)
{
ClientScript.RegisterStartupScript(
GetType(),
Guid.NewGuid().ToString(),
string.Format("alert('{0}');", message.Replace("'", #"\'")),
true
);
}
/// <summary>
/// Finds the control recursive.
/// </summary>
/// <param name="id">The id.</param>
/// <returns>control</returns>
protected virtual Control FindControlRecursive(string id)
{
return FindControlRecursive(id, this);
}
/// <summary>
/// Finds the control recursive.
/// </summary>
/// <param name="id">The id.</param>
/// <param name="parent">The parent.</param>
/// <returns>control</returns>
protected virtual Control FindControlRecursive(string id, Control parent)
{
if (string.Compare(parent.ID, id, true) == 0)
return parent;
foreach (Control child in parent.Controls)
{
Control match = FindControlRecursive(id, child);
if (match != null)
return match;
}
return null;
}
Putting authorization code in a base page is generally not a good idea. The problem is, what happens if you forget to derive a page that needs authorization from the base page? You will have a security hole.
It's much better to use an HttpModule, so that you can intercept requests for all pages, and make sure users are authorized even before the HttpHandler has a chance to run.
Also, as others have said, and in keeping with OO principles, it's better to only have methods in your base page that actually relate to the Page itself. If they don't reference "this," they should probably be in a helper class -- or perhaps be extension methods.
I inherit from System.Web.UI.Page when I need certain properties and every page. This is good for aweb application that implements a login. In the membership pages I use my own base class to get access to Properties like UserID, UserName etc. These properties wrap Session Variables
Here are some examples (sans code) that I use a custom base class for:
Adding a page filter (e.g. replace "{theme}" with "~/App_Theme/[currentTheme]"),
Adding a Property and handling for Auto Titling pages based upon Site Map,
Registering specialized logging (could probably be redone via different means),
Adding methods for generalized input(Form/Querystring) validation, with blanket redirector: AddRequiredInput("WidgetID", PageInputType.QueryString, typeof(string)),
Site Map Helpers, allowing for things like changing a static "Edit Class" into something context related like "Edit Fall '10 Science 101"
ViewState Helpers, allowing me to register variable on the page to a name and have it automatically populate that variable from the viewstate or a default, and save the value back out to the viewstate at the end of the request.
Custom 404 Redirector, where I can pass an exception or message (or both) and it will go to a page I have predefined to nicely display and log it.
I personally like #5 the most because a) updating the SiteMap is ugly and I prefer not to have clutter the page, making it more readable, b) It makes the SiteMap much more user friendly.
,
Please refer Getting page specific info in ASP.Net Base Page
public abstract string AppSettingsRolesName { get; }
List<string> authorizedRoles = new List<string>((ConfigurationManager.AppSettings[AppSettingsRolesName]).Split(','))
if (!authorizedRoles.Contains(userRole))
{
Response.Redirect("UnauthorizedPage.aspx");
}
In derived Page
public override string AppSettingsRolesName
{
get { return "LogsScreenRoles"; }
}

Categories

Resources