I've got a client that, during testing, is giving me conflicting information. I don't think they are lying but more confused. So, I would like to setup some simple auditing in my ASP.Net application. Specifically, right when any page is called, I want to immediately insert the Querystring and/or form POST data into a log table. Just the raw values.
Querystring is easy. But there doesn't seem to be a way to get the raw form POST'ed data without using BinaryRead, and if I do that, then I screw myself out of using the Request.Form collection later on.
Does anyone know a way around this?
EDIT: tvanfosson suggested Request.Params. I was looking for something that was easier to use (like Request.Querystring, only for POST), but I guess I could just as easily loop through all params and build a string of name=value&, etc).
You can create a custom HttpModule to capture all request made to your application so you don't need to touch every page and you can use it only during testing just not to slow down performance in production.
A sample implementation would be:
public class CustomModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.EndRequest += new EventHandler(context_BeginRequest);
}
private void context_BeginRequest(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
// you can use the context.Request here to send it to the database or a log file
}
}
You need to add the module to your web.config
<httpModules>
<add name="CustomModule" type="CustomModule"/>
</httpModules>
All of the form data should be in Request.Params. You'd need to do this on every page, though or maybe use an HttpModule.
[EDIT] If you want to get the form parameters separately use Request.Form, along with Request.QueryString
I would recommend implementing and HttpHandler or an HttpModule for this type of scenario. You can get to the POST Data from the Page_Load event but implementing this logging facility here is not as maintainable.
Related
I am maintaining a customer Classic ASP website, and some ASP.NET code was found in a specific place.
I need someone to help me understand the meaning of each line, because I will have to replace this ASP.NET code with Classic ASP functions.
From my understanding, here is what the code performs :
Get the Request.QueryString url, and put it into a variable named str
Redirect (send a HTTP 302) to the Url-Decoded value of str
I would be sure not missing anything else. Is my understanding full and complete ?
Thank you all .NET folks :)
<%# WebHandler Language="C#" Class="GenericHandler1" %>
using System;
using System.Web;
public class GenericHandler1 : IHttpHandler {
public void ProcessRequest (HttpContext context) {
string str = context.Request.QueryString.Get("url");
// context.Response.Redirect( context.Server.UrlDecode(str));
HttpContext.Current.Response.Redirect(context.Server.UrlDecode(str), false);
}
public bool IsReusable {
get
{
return false;
}
}
}
Your understanding is correct. This is a simple HTTP Handler that decodes URLs and redirects the request to the decoded location.
This is not strictly required in many modern sites but it is a hack that can simplify interpreting url parameters if your site does a lot of it from first principals or in scenarios where you believe the original parameters might be double encoded.
To fully replicate the implementation, you probably don't need to replicate this code at all, not in a global sense. Instead look into the web.config or global.asax.cs or if this is more recent look for startup.cs in one of those files should be the registration for this handler, look for any references to GenericHandler1. When you find that code, you will have found the rest of the implementation detail that you may need to consider implementing.
This is a strange thing to ask, "replicate an ASP.Net website in classic ASP". I'm sure you have your business reasons, but have you instead considered upgrading to an OWIN implementation, perhaps with ASP.Net Core? This is usually the easier option if your requirement is to deploy to non IIS host.
I'm not sure of the best way to accomplish my goal. Looking for insight. I'm familiar with WebAPI services consumed through WPF and Silverlight but this is my first run at ASP and MVC.
I am building a site to verify contents of a shipment against an electronic manifest (EDI 856). I have a page that displays the shipping data and I need the users to scan each item barcode in the container. I would then like to pass that barcode to a service, verify the item belongs in that shipment and then update the page to show as much.
My plan was to have a single text box into which the user could scan/type the barcode and then submit that data to a WebAPI service which would verify the information and then probably use SignalR to send a message back to the page and update a grid with the item data.
If this is a decent way to go, I'm just not quite sure how to use ajax to call the WebAPI endpoint and provide the data I need.
I would advise against using SignalR in this situtation. What you need, judging from your description, is the most basic use case of submitting an ajax request and receiving a response.
You are not designing a system where you need the server to initiate communication with the browser or anything like that, where sockets (and SignalR as an abstraction over sockets with fallbacks to less suitable protocols) is a huge overkill.
Don't worry, your use case is rather simple.
It's a little out of scope to describe how to setup a WebApi project, how to configure routing, action names, etc. Simple google searches will surely provide ample quality tutorials on getting started.
I'll just try to explain what the general idea is, with some code samples, to get you thinking in the right direction.
You need to create an ApiController.
The simplest version of that Controller will probably look something like this:
public class ShipmentVerificationController : ApiController
{
//this is the response object you will be sending back to the client website
public class VerificationResult
{
public bool Valid;
}
public VerificationResult GetIsItemValid(string BarCode)
{
bool itemIsValid;
// Implement checks against the BarCode string here
itemIsValid = true;
return new VerificationResult { Valid = itemIsValid };
}
}
Note that the inner class represents the response you will be sending back. It should be properly filled out with additional info if needed and probably put into a separate .cs file in the "Models" folder or where ever you see fit.
I have declared it inside the controller for demonstration purposes only
Once you have a WebApi service deployed, it's really easy to send it data from your website and receive the feedback.
To simplify Ajax requests, jQuery is often used.
Once the user inputs the barcode into a textbox, you can hook up an event to check for return key being pressed (most barcode scanners send the return key command after they input the barcode data) and then write something along the lines of:
var barcode = $("#input-field").val();
$.getJSON( "<url_to_your_webapi_service>/api/ShipmentVerification/GetIsItemValid/" + barcode, function( data ) {
if (data.Valid) {
// great, highlight the item as valid
}
else {
//better indicate an error with the scanned item
}
});
Please note that for simplicity I have not included any error handling, url parameter encoding, and most importantly, zero authorization.
Authorization is very important if you deploy the web service to the open web but still do not want anyone to be able to call it.
You will have to research these topics yourself, but I hope I have presented you the core concepts and logic behind a simple service such as this, so you have a base to start with.
If you come up with specific problems and questions post a new question.
I actually found a more simple way to do this. I nixed the idea of using a WebAPI endpoint and just went with a normal controller. I used ajax to prevent the page from refreshing with the new view, since that view is actually just json data with my return values in it.
I am trying to improve the performance of a large ASP.NET MVC website and I am currently looking for a way of adding a cache busting query string to image requests in such a way that I don't have to go through all the views and CSS and change each image reference.
Desired result
To verify if the cache buster is being added I am using the Firebug extension in Firefox and what I am looking to see is something like this (screenshot taken from another website)
What I've tried
The simplest answer seemed to me to create a custom HttpModule that intercepted any image request and then appended the cache busting query string to the request URL. So I wrote the following class
public class CacheBusterImageHandler : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += this.BeginRequest;
}
public void Dispose()
{
}
public void BeginRequest(object sender, EventArgs e)
{
// This conditional check will need to be modified to capture other image types
// but for testing purposes it is good enough
if (HttpContext.Current.Request.Path.EndsWith(".gif", StringComparison.OrdinalIgnoreCase))
{
// The version number will be generated but again for testing purposes this
// is good enough
var pathWithCacheBuster = string.Format("{0}?v1.0.0.0", HttpContext.Current.Request.Path);
HttpContext.Current.RewritePath(pathWithCacheBuster);
}
}
}
I then registered the module in web.config like this
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="CacheBusterImageHandler" type="MyAssembly.CacheBusterImageHandler" preCondition="managedHandler" />
...
I then verified that the requests were getting processed by the module by using breakpoints, however when I checked in Firebug the image requests did not have the cache buster appended to URL. I then decided to read the documentation for the RewritePath method and found that of course it simply redirects the request but does not alter the requested URL.
Questions
Is there a way in an HttpModule to append the cache buster to the query string?
If not, is there some other way I can achieve the same result without having to modify every reference to an image?
"Is there a way in an HttpModule to append the cache buster to the
query string?"
No. That is far to late in the process. The URL has to be changed when you put it in the page, that's what the browser uses to check if the image is in the cache or not.
"If not, is there some other way I can achieve the same result without
having to modify every reference to an image?"
That depends on how you put the image URLs in the page, but there is no way of changingt he URLs that works for all way to put an URL in the page.
You can make a method that calculates the version number/string to include, and add that to all URLs. That way you only have to make the change once, not every time an image changes.
The method could use the version number or compile time of the assembly if you want to invalidate the cache every time that you deploy the page, or the update time of the image file.
Basically:
<img src="/images/logo.png<%= ImageVersion("/images/logo.png") %>" alt="Logo">
Using something like:
public static string ImageVersion(string name) {
FileInfo info = new FileInfo(HttpContect.Current.MapPath(name));
int time = (int)((info.LastWriteTimeUtc - new DateTime(2000,1,1)).TotalMinutes);
return "?v=" + time.ToString();
}
For my blog I am wanting to use the Output Cache to save a cached version of a perticular post for around 10 minutes, and thats fine...
<%#OutputCache Duration="600" VaryByParam="*" %>
However, if someone posts a comment, I want to clear the cache so that the page is refreshed and the comment can be seen.
How do I do this in ASP.Net C#?
I've found the answer I was looking for:
HttpResponse.RemoveOutputCacheItem("/caching/CacheForever.aspx");
The above are fine if you know what pages you want to clear the cache for. In my instance (ASP.NET MVC) I referenced the same data from all over. Therefore, when I did a [save] I wanted to clear cache site wide. This is what worked for me: http://aspalliance.com/668
This is done in the context of an OnActionExecuting filter. It could just as easily be done by overriding OnActionExecuting in a BaseController or something.
HttpContextBase httpContext = filterContext.HttpContext;
httpContext.Response.AddCacheItemDependency("Pages");
Setup:
protected void Application_Start()
{
HttpRuntime.Cache.Insert("Pages", DateTime.Now);
}
Minor Tweak:
I have a helper which adds "flash messages" (Error messages, success messages - "This item has been successfully saved", etc). In order to avoid the flash message from showing up on every subsequent GET, I had to invalidate after writing the flash message.
Clearing Cache:
HttpRuntime.Cache.Insert("Pages", DateTime.Now);
Hope this helps.
Using Response.AddCacheItemDependency to clear all outputcaches.
public class Page : System.Web.UI.Page
{
protected override void OnLoad(EventArgs e)
{
try
{
string cacheKey = "cacheKey";
object cache = HttpContext.Current.Cache[cacheKey];
if (cache == null)
{
HttpContext.Current.Cache[cacheKey] = DateTime.UtcNow.ToString();
}
Response.AddCacheItemDependency(cacheKey);
}
catch (Exception ex)
{
throw new SystemException(ex.Message);
}
base.OnLoad(e);
}
}
// Clear All OutPutCache Method
public void ClearAllOutPutCache()
{
string cacheKey = "cacheKey";
HttpContext.Cache.Remove(cacheKey);
}
This is also can be used in ASP.NET MVC's OutputCachedPage.
On the master page load event, please write the following:
Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
and in the logout button click:
Session.Abandon();
Session.Clear();
Hmm. You can specify a VaryByCustom attribute on the OutputCache item. The value of this is passed as a parameter to the GetVaryByCustomString method that you can implement in global.asax. The value returned by this method is used as an index into the cached items - if you return the number of comments on the page, for instance, each time a comment is added a new page will be cached.
The caveat to this is that this does not actually clear the cache. If a blog entry gets heavy comment usage, your cache could explode in size with this method.
Alternatively, you could implement the non-changeable bits of the page (the navigation, ads, the actual blog entry) as user controls and implement partial page caching on each of those user controls.
If you change "*" to just the parameters the cache should vary on (PostID?) you can do something like this:
//add dependency
string key = "post.aspx?id=" + PostID.ToString();
Cache[key] = new object();
Response.AddCacheItemDependency(key);
and when someone adds a comment...
Cache.Remove(key);
I guess this would work even with VaryByParam *, since all requests would be tied to the same cache dependency.
why not use the sqlcachedependency on the posts table?
sqlcachedependency msdn
This way your not implementing custom cache clearing code and simply refreshing the cache as the content changes in the db?
HttpRuntime.Close() .. I try all method and this is the only that work for me
I've made a little game in silverlight that records users scores whilst they play.
I decided it would be a lot better if I could implement a leaderboard, so I created a database in mySQL to store all the high scores along with names and dates. I have created some communications to the database in ASP.net. This works and I can simply insert and get data within the code.
It's now time to link the silverlight project with the ASP.net database communications, so I can send the users name and score as variables to my ASP.net code and then it will upload it to the database. That's all I need. Surely there must be an easy way of doing this, I just can't seem to find any ways when researching.
Thanks in advance,
Lloyd
At first you need add Generic Handler to your ASP.Net project.
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string userName = context.Request["user"];
int score = int.Parse(context.Request["score"]);
//And store it in DB
}
}
After you need call this handler from SilverLight app:
string uri = HtmlPage.Document.DocumentUri.ToString();
// Remove the web page from the current URI to get the root URI.
string rootUri = uri.Remove(uri.LastIndexOf('/'),
uri.Length - uri.LastIndexOf('/'));
string diggUrl = String.Format(rootUri + "/" + "test.ashx?user={0}&score={1}", "testuser", "234");
// Initiate Async Network call to Digg
WebClient diggService = new WebClient();
diggService.DownloadStringAsync(new Uri(diggUrl));
here i used Uri Class to send parameter to asp.net, but you can send string format only.
// this code written on Silverlight Button Click Event.
Uri myURI = new Uri(HtmlPage.Document.DocumentUri,String.Format("Report.aspx?brcd={0}&acc={1}&user={2}", Brcd, Acc, User)); HtmlPage.Window.Navigate(myURI, "_blank");
below code is written on Asp.net page_load or page init event
Brcd = Request.QueryString["brcd"];// brcd value accept here.
acc= Request.QueryString["ACC"];`
user= Request.QueryString["User"];
in above code we accept the silverlight parameter in asp.net but in [] bracket put name as it is use in silverlight page because it case sensitive.
By ASP.NET, do you mean an ASP.NET Webforms app?
If so, an ASP.NET Webforms app is a method of building a UI. What you need is an API, for your Silverlight app to use programatically. For this purpose you may want to consider building an ASP.NET Webservice instead, which provides an API over HTTP.
What do you need its to send data to web server from a Silverlight application, right?
You can:
Call Javascript functions from Silverlight and, there, do a postback
Call web services with Silverlight, but make sure its in same server which your SL application came from, or you will face some XSS issues.
An easy way to do this is to have your Silverlight code create a REST URL by encoding the information into the query string, and invoking an .aspx page on the server. The page wouldn't need to return any markup; it would just handle the back-end stuff and return.
Alternatively, you could make a web service call from Silverlight to your back end.
I prefer the latter approach. It's a little more work the first time through, but it's also more general purpose and makes for generally better code in the long run.
Although technically you could use JavaScript, I wouldn't suggest it; why go backwards in tech if you don't have to?