passing Objects, variables from ASP.net web forms to RazorView - asp.net

I currently wanted to upgrade an old ASP.NET Webforms which is using (NVelocity template) to RazorView(template) MVC is not required at the moment. BusinessLogic is already in the code behind of aspx.cs file.
Is it possible to pass Objects and Variables from Webforms to RazorViews:
I have already tried using session(Not Workerd) and querystring(Worked). passing data using Querystring works but on cost of rewriting BusinessLogic which is not an option.
Example:
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
string myData = "DATA FROM ANOTHER UNIVERSE";
ArrayList myList = new ArrayList();
//Possible Function to invoke and pass data to RazorView
RenderDataBridgeToRazorView("defaultRazorTemplate", myData);
//Another way to look at the same functions with Objects
RenderDataBridgeToRazorView("defaultRazorTemplate", myList);
}
}

Related

How to make a ASP.NET Webforms application testable?

I am looking at a legacy enterprise application, which written using ASP.NET. No controls or web forms. This is how it works:
EmployeeList.aspx:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="EmployeeList.aspx.cs" Inherits="EmployeeList" %>
EmployeeList.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
// Security Check
// Load Template, get version 1.4 of active employee list
StringBuilder template = GetTemplate("Employee", "ActiveList", "1.4", true);
// Get list from database
using(SqlDataReader objReader = GetListFromDB())
{
while(objReader.Read())
{
//fills data
TUtils.Replace(template, ROW, "%name%", objReader[0]);
}
}
// return response
Response.Write(template.ToString());
}
private StringBuilder GetTemplate(string x, string y, string v, bool z);
{
// returns template
}
private SqlDataReader GetListFromDB() {
// returns data reader
}
My question is, since we are not using web forms, is there a way to introduce NUnit in this event driven model (as shown above)?
Also, please avoid suggestions to move to ASP.NET MVC or other patterns, which we are considering, but wondering is there any way to convert this enterprise application testable.
This is absolutely possible. You should have a look on implementing MVP pattern with ASP.NET Webforms. There are several open source implementations but you can do a smaller specialized on your your own.
The basics are to move your code behind logic to a presenterclass. The presenter class has a reference to the page implementing an interface. The trick in your case will be to Mock the Page.Response object for your test. Thats why it´s hard to unit test it right way. The PageResponse Property contains a object deriving from HttpResponseBase and that´s the baseclass you should Mock in your tests and do your asserts on with your example. You could start with that and then extend your presenter with functionalty like Session, Request etc.
If you don´t have any markup at all probably you can just create the presenter in the view constructor and don´t bother of having and reference to the view.
To clarify: The big trick is to get the code out of the aspx.cs file. That beast is not testable.
Sample base class for Presenters:
public class Presenter<T> where T : class, IView
{
protected readonly T View;
protected Presenter(T view, ILogger logger)
{
View = view;
}
public virtual void page_PreRender(object sender, EventArgs e)
{
}
public virtual void page_Init(object sender, EventArgs e)
{
}
public virtual void page_Load(object sender, EventArgs eventArgs)
{
}
public HttpContextBase HttpContext { protected get; set; }
protected HttpRequestBase Request
{
get { return HttpContext.Request; }
}
}
Since most of your code is in the code-behind, I dont think that the usual testing approach with NUnit / Visual Studio testing framework will work well.
However, I think one possible approach is to use UI Testing frameworks like WATIN / Selenium. This will enable you to still write tests for the various functionality.
I have done something similar in the past by basically writing a test case for every UI action that results in a server postback. May not be ideal but it does allow you to automate your testing.

using a static member in WebApp

I have this code
//file Globals.cs in App_Code folder
public class Globals
{
public static string labelText = "";
}
and a simple aspx page which has textbox, label and button. The CodeFile is:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = Globals.labelText;
}
protected void Button1_Click1(object sender, EventArgs e)
{
Globals.labelText = TextBox1.Text;
}
}
That is when I click on the button the Globals.labelText variable initializes from the textbox; the question is: why when I open this page in another browser the label has that value, which I set by the first browser, that is the static member is common for the every users. I thought that the every request provides in the individual appDomain which created by the individual copy of IIS process. WTF?
Yes you may use static variable to store application-wide data but it is not thread-safe. Use Application object with lock and unlock method instead of static variables.
Take a look at ASP.NET Application Life Cycle Overview for IIS 7.0 and ASP.NET Application Life Cycle Overview for IIS 5.0 and 6.0
No, static in this case is static in that manner only for the lifecycle of the process the request lives on. So this variable will be static the entire time you're processing a single request. In order to have a "static" variable in the manner you describe, you'd have to make it an application variable. Something like this:
//file Globals.cs in App_Code folder
public class Globals
{
// I really recommend using a more descriptive name
public static string LabelText
{
get
{
return Application("LabelText") ?? string.Empty;
}
set
{
Application("LabelText") = value;
}
}
}
By making it an application variable it should survive multiple page requests. A vulnerability it has though is that it will not survive an application pool recycle, and for large applications this can be problematic. If you truly want this variable to behave in a static manner reliably you're probably better off storing its state in a database somewhere.

How to pass multiple parameters to a crystal report?

I have a crystal report in my asp.net web application which has a lot of report parameters (about 15). Previously I was using querystring to pass them but it was being unsecure.
Now I am mapping all parameters to a Hashtable, storing them in session & passing to the report viewer. Now If user opens multiple instance of reports in different browser tabs, the session values get messed up. When I navigate pages, wrong reports are displayed.
Please advise me a good method to pass my parameters to report.
Damien.
How about creating a simple DTO for storing all report parameters. Save this DTO in session and access in report viewer page where your viewer control resides.
To cross over the session issue when user opens multiple instances in browser, you can do a simple trick. When user provides parameter, and clicks on "Show Report", at that point create a guid, store value inside the session using key as this guid, and pass this guid as query string parameter to your report viewer page. This way each instance of report viewer page is aware which session value to be brought out.
Something like this
public class AttendanceDTO
{
public int EmployeeId {get;set;}
public string Month {get;set;}
}
And then in your "Report parameter page"
/* JUST NOTEPAD CODE, SYNTAX MIGHT VARY */
protected override ShowReport_Click(object sender, EventArgs e)
{
string guid = new Guid();
AttendanceDTO dto = new AttendanceDTO()
{ EmployeeId = txtEmployee.Text;
Month = txtMonth.text
};
session[guid] = dto;
Response.Redirect("ReportViewer.aspx?Guid=" + guid);
}
And then inside your Report Viewer Page
string guid = Request.QueryString["Guid"]; //Null check etc..
AttendanceDTO dto = (AttendanceDTO) session[guid];
//Provide dto values as parameters to your report viewer control and then clean the session
[You would need to make sure that you clear out the respective session value after you get it used.]
[Above code is just from notepad to give you an idea. On top of this you can bring more innovation]
Session Objects are shared among multiple tabs of same browser since server stores only one session cookie for a browser. So it is pretty obvious for the values to messup in several tabs on single browser.
One of the possible solution:
Use ViewStates instead of session to store HashTable.
Refer the code below for a demo, I have used ArrayList instead is HashTable for the sake of simplicity.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ViewState["ht"] = new ArrayList();
//initialize viewstate with arraylist on first pageload.
}
}
protected void btnAddElement_Click(object sender, EventArgs e)
{//adding new elements to the arraylist
if (ViewState["ht"] != null)
{
ArrayList ht = (ArrayList)ViewState["ht"];
ht.Add(TextBox1.Text);
ViewState["ht"] = ht;
}
}
protected void Button2_Click(object sender, EventArgs e)
{
if (ViewState["ht"] != null)
{
ArrayList ht=(ArrayList)ViewState["ht"];
foreach (object a in ht)
{//write code to pass parameters to the crystal report
Response.Write(a);
}
}
}
}
Since Viewstates work at page level, therefor the values in the collection will not mess up this time.
Hope this helps.

page event when using page methods?

I have the following that I'm using in every page:
public partial class Pages_MyPage : System.Web.UI.Page
{
ViewUserPreferencesModel TheUserPreferences;
Protected void Page_Load(object sender, EventArgs e)
{
TheUserPreferences = (ViewUserPreferencesModel)Session["SessionUserPreferences"];
And then I use a Page Method like this:
[WebMethod]
public static string GetAppointements(string DateInput)
{
ViewUserPreferencesModel TheUserPreferences = (ViewUserPreferencesModel)HttpContext.Current.Session["SessionUserPreferences"];
My question is this: Do I need to include the statement that loads user preferences when I run the page method or are the statements in the Page_Load event triggered when the page method is called, and if they are, will the variable be populated?
Thanks.
No, Page Methods do not follow the ASP.NET page lifecycle. However, even if they did, your TheUserPreferences variable won't be accessible in the static context.

Callling business logic layer method from PageMethods

I've a static page method in web form application and I want to call method on private class level variable from it as shown below. I'm using jQuery to call the page method.
private readonly ICatalogBLL _catalogBLL = new CatalogBLL();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
_catalogBLL.GetSomething();
}
}
[WebMethod]
public static UpdateSomething(int i)
{
//Want to do as below. But can't call it from a static method.
_catalogBLL.UpdateSomething();
}
UPDATE
If I call it as said by John Saunders, won't it use the same instance for requests from different users as it is within a static method?
You can't. The page method is static. Your _catalogBLL is an instance member.
However, since you create a new instance of CatalogBLL on every request, why not do so once more?
[WebMethod]
public static UpdateSomething(int i)
{
CatalogBLL catalogBLL = new CatalogBLL();
catalogBLL.UpdateSomething();
}
You can't call because pagemethods are static...
A static method is simply one that is disassociated from any instance of its containing class. The more common alternative is an instance method, which is a method whose result is dependent on the state of a particular instance of the class it belongs to.
Look at John saunder's answer..

Resources