need suggestion on C# coding (efficiency) - asp.net

In my code I have a dropdown selection and upon selection from dropdown the code performs further processing and generates report/data.
Further, the entire program depends on data which is gathered from 3 different operation
Operation1: processing a text files of size of size > 6MB
Operation2: SQL Query to a DB (Query takes around 1 minute)
Operation 3: HTTP POST request to server (The main costliest part of the programe)
So, to make it efficient I am thinking to perform this operation only once and use the data for all the different selection from dropdown.
Question is how can I do so as below:
I can't put it in "page_load" event because every time page loads the operations will carry out
I can't put it inside "dropdownlist_selectedindexchanged" event because then it will be same as #1.
I thought of doing it in "page_load" as below
void Page_Load(object sender, EventArgs e)
{
if(!ispostback)
{
Operation1();
Operation2();
Operation3();
}
}
This is fine; the operations gets performed only once and I can use the data throughout, but then my page will take time to load as the operations takes time.
Is there any other way I can achieve what I want? Please let me know.
Thanks,
Rahul

If the data set will not change, you probably could manage to do it once at Application_Start().
Edit - something like this (typing from memory and away from VS, i do VB):
Protected void page_load(object sender, eventargs e)
{
// the name can be anything
if (!System.Web.HttpContext.Current.Session["data_cache_filled"])
{
// code to fill the cache.
// ...
//mark it as filled
System.Web.HttpContext.Current.Session["data_cache_filled"] = "yes";
}
}

Cache it. Using the CacheHelper class from here, you could do:
internal List<Employee> Operation1()
{
List<Employee> employeeData;
if (!CacheHelper.Get("employeeData", out employeeData))
{
employeeData = (from x in db.Employees select x).ToList(); // or whatever
CacheHelper.Add(employeeData, "employeeData");
}
return employeeData;
}

Related

How to get Calling Gridview name in ObjectDataSource Selecting event

I have 2 gridviews, gv1 and gv2 and an ObjectDataSource with the id ods1. Both the gridviews are pointing to DataSourceID="ods1".
My question is, how do I know in selecting event of an ObjectDataSource that which gridview has called ods1. I want to set input parameters based on which gridview has made a call to the ods1.
I think this is not easily possible and it feels like it would be against the idea behind ODS.
You can delegate two ObjectDataSources to get the data from THE SAME repository class but still, you need two different data sources if you want to have two different sets of parameters. Thus, you do not duplicate code as the repository code is shared between object data source instances.
Warning: Hack ahead
I tend to agree with Wiktor Zychla's answer, but if you really need to do this...
The only thing I can think of to accomplish this would be to handle the "DataBinding" event of each of your GridViews, and set a session variable to indicate which one is about to call the ObjectDataSource "Selecting" event.
So you would have your GridView methods:
protected void gv1_DataBinding(object sender, EventArgs e)
{
Session["currentGridID"] = "gv1";
}
and
protected void gv2_DataBinding(object sender, EventArgs e)
{
Session["currentGridID"] = "gv2";
}
And then, your ObjectDataSource could check that Session variable, to see which ID is in it while the ObjectDataSource is firing this time:
protected void ods1_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
{
if(Session["currentGridID"] == "gv1")
{
}
else
{
}
}
To get the name of the gridview which call the objectdatasource
You can do something like:
string CallingGridName = ((ObjectDataSourceID)sender).ID;

hook POST parameters in asp.net

I'm recently mining a website to build some database. I already built a python script parsing retrieved information but the problem is that it requrires a query word to retrieve web pages which contain information I want to see. And this page is in POST method so I cannot see how this page retrieves a page list.
To describe an outline for your clear understanding:
1. on inputKeyword.aspx : This contains a form to input a query(let's say ID)
When I input an ID and press search, it retrievs a
relevant list
2. Press Search
3. on inputKeyword.aspx : A relevant list is showed on the same aspx page
(which means POST method), so I cannot see how this query
works on inputKeyword.aspx page.
It would be so much easier if this webpage is in GET method, since I can simply hook a url with queries, but it's not possible in POST method.
Is there any way that I can open step #3 skipping step #1 and #2?
The webpage is built in asp.net but there's no restriction on languages as long as there's way to do this.
If I understand correctly you want to be able to accept a an ID as part of your query string. eg
http://your.domain.com/inputKeyword.aspx?ID=555
So in the pages load event you can check the request object for query params, ie Request.QueryString[param] as the following example shows
protected void Page_Load(object sender, EventArgs e)
{
string id = Request.QueryString["ID"];
if (!string.IsEmptyOrNull(id))
{
//do something with the requested identifier
}
}
Note: you can use Page.IsPostBack() to determine if the page is being hit for the first time or is posting back as a result of a button click.
To get your Search button to behave correctly you have a couple of options. For example; you can use javascript to capture the buttons onclick event and redirect the page to itself with the url amended to include the identifier from the id textbox.
But perhaps the following is the easiest, keeping the code all server-side:
private _identifer string;
protected void Page_Load(object sender, EventArgs e)
{
string id = Request.QueryString["ID"];
if (!string.IsEmptyOrNull(id))
{
_identifer = id;
}
}
protected void SearchButton_Click(object sender, EventArgs e)
{
_identifer = IdentiferTextbox.Text;
}
protected void Page_PreRender(object sender, EventArgs e)
{
if (!string.IsEmptyOrNull(_identifer))
{
PopulateListForidentifer(_identifer);
}
}
Basically the example shows that you can cope with scenarios. ASP.Net's page life cycle means that events are processed in the following order Page_Load -> Control Events (eg button click) -> Page PreRender.
If the page is hit for the first time without an identifier in the url, PopulateListForidentifer method isn't called since _identifer is never set.
But if the url contains an identifier then _identifer is set in the page load event, when the page pre-render is called PopulateListForidentifer will be called.
Finally if the page is posting back to itself because the search button has been hit then the click handler is called and _identifer is set to the content of the IdentiferTextbox; the pages prerender is called and also PopulateListForidentifer. Note this would override the point about ie when the identifer was passing as part of the url.
From what I understand, it seems you want to simulate the HTTP Post operation in your Search form, where by without entering the ID and clicking search, you directely want to have access to the search results.
Here is a Blog Post by Scott Hanselman, where he discusses a similar topic using WebClient.
You may also want to check this thread

Ajax Control Toolkit AsyncFileUploader Control and viewstate/session Issue

in my project i need to upload files so i decided to use the uploader provided by asp.net ajax controls AsyncFileUPloader control.
there are four blocks. every block contains two such uploaders
so i decided to utilize the power of asp.net web user controls.
i wrapped the required form fields in my user control called DesignUploader.ascx
now i have to put the four instances of this control on my aspx page
please refer the snap below
my problem starts here i have to insert the fileurl to the database and each of the block generates unique id and id value changes after uploading the file to the server. i noticed that viewstate does not work for me in case of asyncfileuploader it clears the viewstate because it does the secret postback to the server behind the scenes. now only option left for me is to use session but when user uploads the files in two blocks one after another then filepath from second/third consecutive blocks overwrite my session. i don't know how many blocks user can use to upload the designs he may use 1 only or he may use all four.
There would be a final submit button in the bottom of the page on click of which i have to insert data to database.
so when i tried to save the data to database the session stores the value of the recently uploaded file path for all the records my problem lies here
i don't know if i was able to describe my problem in correct manner or not please excuse me if it is not clear and post comment if required.
Note: I can not change the UI because client insists for this only :(
any quick work around would be appreciated much
Thanks
Devjosh
I believe you saving file path to session in a wrong way and it's impossible to recognize where is an error without code.
All the way, in my opinion better don't persist file path in session but use client side for that purpose instead. You can add two hidden fields to DesignUploader.ascx control and set their values in UploadedComplete event handler.
public partial class DesignUploader : System.Web.UI.UserControl
{
private static readonly string AppDataPath = HttpContext.Current.Server.MapPath("~/App_Data/");
public string FirstFilePath
{
get
{
return Server.UrlDecode( FirstFilePathHiddenField.Value);
}
}
public string SecondFilePath
{
get
{
return Server.UrlDecode(SecondFilePathHiddenField.Value);
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
FirstFileUpload.UploadedComplete += FirstFileUpload_UploadedComplete;
SecondileUpload.UploadedComplete += SecondileUpload_UploadedComplete;
}
void FirstFileUpload_UploadedComplete(object sender, AjaxControlToolkit.AsyncFileUploadEventArgs e)
{
var fullPath = Path.Combine(AppDataPath, Path.GetFileName(e.FileName));
FirstFileUpload.SaveAs(fullPath);
SaveFilePathToHiddenField(FirstFilePathHiddenField.ClientID, fullPath);
}
void SecondileUpload_UploadedComplete(object sender, AjaxControlToolkit.AsyncFileUploadEventArgs e)
{
var fullPath = Path.Combine(AppDataPath, Path.GetFileName(e.FileName));
SecondileUpload.SaveAs(fullPath);
SaveFilePathToHiddenField(SecondFilePathHiddenField.ClientID, fullPath);
}
private void SaveFilePathToHiddenField(string fieldId, string pathValue)
{
var script = string.Format("top.$get('{0}').value = '{1}';", fieldId, Server.UrlEncode(pathValue));
ScriptManager.RegisterStartupScript(this, this.GetType(), "setPath", script, true);
}
}

GridView_RowCommand event fired again on page refresh

I have implement GridView Row Editing feature in my .net application using <asp:CommandField.
I clicked on Update button to save the record after editing the row.Now if i refresh the page or press F5 GridView_RowCommand fired again.
How can we avoid this.Is there any mechanism to identify when user press F5 OR refresh the page.Is there any method in client side or in server side.
Not exactly the best "technical" solution to your problem but you could always just do a Response.Redirect(Request.RawUrl) once you have finished doing anything you need to do in your RowCommand
Like I said, it's not the best "technical" solution but it is a solution
Dave
One method of capturing this is to maintain a session variable that is related to the page in question. In the session variable you would keep some kind of state enumeration, key or string that would determine the last action taken. You could even use a simple incremented counter, and if you ever received a postedback counter that was equal to the session variable it would indicate a page refresh rather than a new action.
Session["LastInsertedItem"] = null;
MyCustomObjType myCustomObject;
protected void Page_Load(object sender, EventArgs e)
{
myCustomObject = Session["LastInsertedItem"] as MyCustomObjType;
}
void GridView_RowCommand(Object sender, GridViewCommandEventArgs e)
{
If(myCustomObject == null || //!(compare your value with myCustomObject.field) )
{
// do your operations and save the values to myCustomObject and save that object back to Session.
}
else
{
// It is refreshed or same data is being insterted - don't know if second option is possible in your case.
}
}

Global.asax, global variables, and editing with code

I have two questions:
1) I have a few global variables for my website declared in my global.asax file. They are simple, small key/value pairs and there are only a few of them. Is this a good practice for values that are small and need to be accessed by almost every page on my website? Storing them in the database and requiring a db lookup seems as thought it would waste resources for values that don't change rapidly.
2) If one of the values changes once per week, is it possible to allow a user to edit the global variable with a form or some other means?
Example:
<script runat="server">
Overloads Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
Application("default_scoring_id") = 3
Application("week_current") = 3
End Sub
</script>
In the above example, the system needs to know which week (out of 15 of them) that the current date is within. So, once every Monday morning, the "week_current" value needs to change.
I can easily do this, but is there a way to give a user access to changing this value without touching the code?
The typical practice is to put these into the web.config, which can be edited. These <appSettings> values will then be available on every page, yet the file can be edited.
1) Good practice is usually to store those sort of values in the web.config. See here and here for some guides.
2) a) If you store this in the web.config it will be easily updatedable without the need for recompiling and the web application should immediatly pick up the changes.
b) Does updating something like the 'week number' really need to be a manual process? It sounds a bit error prone and i would suggest automating this if at all possible by calculating it based on the current date.
I would consider using the built in Cache (System.Web.Caching.Cache)
That way you can store them where ever you want (say in a database), change them from within the app easily, and have quick and cheap retrieval.
From within a class which inherits from BasePage use the given Cache object (eg Cache.Add(..)) and from elsewhere use HttpContext.Current.Cache (eg. HttpContext.Current.Cache.Remove(Key))
The other answers suggest the different ways this can be done, and must be done. But, even then if you want to allow the user to edit the global variable, you'll have to take a lock or Mutex on a shared object, change the value of your global variable, and release the lock or Mutex.
lock(globalsharedobject) //This is C# code.
{
Application("default_scoring_id") = 3;
}
Web.config is the .NET way, or ASP.NET way, it's not always the most efficent or most suitable.
You're Global.asax file is much more than some events, you can put static data in any class that subclass System.Web.HttpApplication and inherit that in your Global.asax file.
The HttpSessionState and HttpApplicationState are relics, from the classic ASP time and you would do well to avoid them, becuase the serve no real purpose.
Depending on the type (System.Type) of your objects you can design your own strongly typed objects that store information about your application and session, for application level data a bunch of static fields would be enough.
They have to be static becuase each HttpModule as well as HttpApplication instance are pooled object, so to avoid that confusion, make sure your persistent data is stored in a static or several static dicionaries. But be aware of concurrency issues when modyfying these collections. A good strategy is to lock the object, only for the duration you're modifying it and make sure you don't call any other code while modyfiny the collection, a simple swap idiom, might be helpful here, it's fast and it's a non-deadlock guarntee.
<%# Application Language="C#" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
}
void Application_End(object sender, EventArgs e)
{
// Code that runs on application shutdown
}
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
}
void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
}
void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.
}
protected void Application_BeginRequest(Object sender, EventArgs e)
{
Context.Items.Add("Request_Start_Time", DateTime.Now);
}
protected void Application_EndRequest(Object sender, EventArgs e)
{
TimeSpan tsDuration = DateTime.Now.Subtract((DateTime)Context.Items["Request_Start_Time"]);
Context.Response.Write("<b>Request Processing Time: From Global.asax file " + tsDuration.ToString());
Application["time"] = tsDuration.ToString();
}
</script>

Resources