UnitTest Method for AJAX JSON Calls to an API - asp.net

I am trying to write test cases for our AJAX calls to our API. Doing a simply web request and response. My question is with regard to the response. Is there a simpler way to pull out the response JSON values? Is the best way to do this sort of thing? I know we could us JQuery, but wanted to use Microsoft Testing framework.
[TestMethod]
public void TestMethod1()
{
string brand = "KEWL";
string BRAND = "";
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://203.135.xx.138:4040/api/v1/subscriptions/signup.format");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = #"{" +
" 'api_key': '91230D10-247C-11E1-83FF-9B9C4824019B'," +
" 'phone': '12122639043', " +
" 'dob': '11231954', " +
" 'subscriptions': [ " +
" {" +
" 'Brand':'" + brand + "', " +
" 'campaign':'BTLNDN', " +
" 'groups':[" +
" {" +
" 'group': 'BTLALL'," +
" 'subscribed':true" +
" } " +
" ]," +
" 'lang': 'en' " +
" }" +
" ] " +
" }";
streamWriter.Write(json);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var responseText = streamReader.ReadToEnd();
JavaScriptSerializer serializer = new JavaScriptSerializer();
Dictionary<string, dynamic> dc = serializer.Deserialize<Dictionary<string, dynamic>>(responseText);
var kev = dc;
foreach (var key1 in dc.Keys)
{
var value3 = dc["ReturnData"]["subscriptions"];
BRAND = value3[0]["brand"];
// var groups = value3[0]["groups"];
}
}
Assert.AreEqual(brand, BRAND);
}

The idea of unit testing ASP.NET MVC methods is that you can run the test without using any Http request or respond functionality.
Suppose you have the following method:
public class MyController : Controller
{
public ActionResult MyAjax()
{
return Json(new { Test = "Test" });
}
}
You can test it with this code:
[TestMethod]
public void MyTest()
{
MyControllercontroller = new MyController();
JsonResult json = controller.MyAjax() as JsonResult;
Assert.IsNotNull(json);
dynamic data = json.Data;
Assert.AreEqual("Test", data.Test);
}
To use the dynamic keyword you have to make sure that your test project can see the internals of your web project (this is because anonymous types are declared internal). You can do this by adding: [assembly: InternalsVisibleTo("YourTestProject")] to the AssemblyInfo.cs file of your web project.

Related

HTML DOM not working with JavaScript page

Getting HTML DOM from websites that work with client-side (JavaScript)
It doesn't work because
<div class="currTableContainer" id="divCurrTableContainer">
is empty. There is nothing in it. You wont find a table in it. Hence the nullpointer. The HTML you're looking for is generated by a script(ajax).
Check the loaded HTML to confirm.
Because I was bored I decided to finish your homework. You can't use HAP in this case. You have to use the ajax service they provided. Also better since the data is prone to change a lot. The code that is used on the site(ajax script) looks like this:
$("document").ready(function () {
$.ajax({
type: "POST",
url: '/_layouts/15/LINKDev.CIB.CurrenciesFunds/FundsCurrencies.aspx/GetCurrencies',
async: true,
data: "{'lang':'" + document.getElementById("ctl00_ctl48_g_5d7fc52f_a66d_4aa2_8d6c_c01fb4b38cb2_hdnLang").value + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
if (msg.d != null && msg.d.length > 0) {
var contentHTML = "<table class='currTable' cellspacing='0' rules='all' style='border-width:0px;border-collapse:collapse;'>"
+ "<tbody><tr class='currHeaderRow'>"
+ "<th scope='col'>" + document.getElementById("ctl00_ctl48_g_5d7fc52f_a66d_4aa2_8d6c_c01fb4b38cb2_hdnCurrency").value + "</th><th scope='col'>" + document.getElementById("ctl00_ctl48_g_5d7fc52f_a66d_4aa2_8d6c_c01fb4b38cb2_hdnBuy").value + "</th><th scope='col'>" + document.getElementById("ctl00_ctl48_g_5d7fc52f_a66d_4aa2_8d6c_c01fb4b38cb2_hdnSell").value + "</th>"
+ "</tr>";
for (var i = 0; i < msg.d.length; i++) {
if (msg.d[i].CurrencyID.length > 0) {
contentHTML += "<tr class='currRow'>"
+ "<td>" + msg.d[i].CurrencyID + "</td><td>" + msg.d[i].BuyRate + "</td><td class='lastCell'>" + msg.d[i].SellRate + "</td>"
+ "</tr>";
}
}
contentHTML += "</tbody></table>";
$("#divCurrTableContainer").html(contentHTML);
if ($(".bannerElements").length > 0)
FixCurrenciesRatesScroll();
}
},
error: function (msg) {
}
});
});
As you can see the script uses an URL from a different part of the site to update their currency. In order to fetch it you just make http request with the following JSON {"lang":"en"}. I have translated the script into it's equivalent in C# below. The response from the http request will be JSON formatted. Which means you will have to create a class that can be used to serialize the data. I recommend you look at Newtonsoft for this since I can't do all your homework.
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
namespace test
{
class Program
{
public static void Main(string[] args)
{
try
{
string webAddr = "http://www.cibeg.com/_layouts/15/LINKDev.CIB.CurrenciesFunds/FundsCurrencies.aspx/GetCurrencies";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
httpWebRequest.Expect = "application/json";
string datastring = "{\"lang\":\"en\"}";
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] data = encoder.GetBytes(datastring);
httpWebRequest.ContentLength = data.Length;
httpWebRequest.GetRequestStream().Write(data, 0, data.Length);
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var responseText = streamReader.ReadToEnd();
Console.WriteLine(responseText);
//Now you have your response.
//or false depending on information in the response
}
}
catch (WebException ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
}

How to add file attachment to Email message sent from Razor page (with ASP.NET Core and MailKit)

The following is a method for sending an Email from a Razor page in ASP.NET Core. I need to use MailKit since System.Net.Mail is not available in ASP.NET Core.
Despite much research, I haven't been able to figure out a way to include the image to the Email. Note that it doesn't have to be an attachment - embedding the image will work.
public ActionResult Contribute([Bind("SubmitterScope, SubmitterLocation, SubmitterItem, SubmitterCategory, SubmitterEmail, SubmitterAcceptsTerms, SubmitterPicture")]
EmailFormModel model)
{
if (ModelState.IsValid)
{
try
{
var emailName= _appSettings.EmailName;
var emailAddress = _appSettings.EmailAddress;
var emailPassword = _appSettings.EmailPassword;
var message = new MimeMessage();
message.From.Add(new MailboxAddress(emailName, emailAddress));
message.To.Add(new MailboxAddress(emailName, emailAddress));
message.Subject = "Record Submission From: " + model.SubmitterEmail.ToString();
message.Body = new TextPart("plain")
{
Text = "Scope: " + model.SubmitterScope.ToString() + "\n" +
"Zip Code: " + model.SubmitterLocation.ToString() + "\n" +
"Item Description: " + model.SubmitterItem.ToString() + "\n" +
"Category: " + model.SubmitterCategory + "\n" +
"Submitted By: " + model.SubmitterEmail + "\n" +
// This is the file that should be attached.
//"Picture: " + model.SubmitterPicture + "\n" +
"Terms Accepted: " + model.SubmitterAcceptsTerms + "\n"
};
using (var client = new SmtpClient())
{
client.Connect("smtp.gmail.com", 587);
// Note: since we don't have an OAuth2 token, disable
// the XOAUTH2 authentication mechanism.
client.AuthenticationMechanisms.Remove("XOAUTH2");
// Note: only needed if the SMTP server requires authentication
client.Authenticate(emailAddress, emailPassword);
client.Send(message);
client.Disconnect(true);
return RedirectToAction("Success");
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + ": " + ex.StackTrace);
return RedirectToAction("Failure");
}
}
else
{
return View();
}
}
This is from the FAQ on Mailkit github repo, and seems to cover the full process.
https://github.com/jstedfast/MailKit/blob/master/FAQ.md#CreateAttachments
var message = new MimeMessage ();
message.From.Add (new MailboxAddress ("Joey", "joey#friends.com"));
message.To.Add (new MailboxAddress ("Alice", "alice#wonderland.com"));
message.Subject = "How you doin?";
// create our message text, just like before (except don't set it as the message.Body)
var body = new TextPart ("plain") {
Text = #"Hey Alice,
What are you up to this weekend? Monica is throwing one of her parties on
Saturday and I was hoping you could make it.
Will you be my +1?
-- Joey
"
};
// create an image attachment for the file located at path
var attachment = new MimePart ("image", "gif") {
ContentObject = new ContentObject (File.OpenRead (path), ContentEncoding.Default),
ContentDisposition = new ContentDisposition (ContentDisposition.Attachment),
ContentTransferEncoding = ContentEncoding.Base64,
FileName = Path.GetFileName (path)
};
// now create the multipart/mixed container to hold the message text and the
// image attachment
var multipart = new Multipart ("mixed");
multipart.Add (body);
multipart.Add (attachment);
// now set the multipart/mixed as the message body
message.Body = multipart;

asp.net web service executed more than one time

I have a web service .asmx that I call from an android mobile application. it return a random number to the android application, and send the same number using sms.
My problem that some times the web service is executed more than one time in the same time and returning the same random number. so the sms is sent more than one time all in one request.
I have two files one is the one I call from my app getRandomNumber.asmx and the second is getRandomNumber.cs the file that generate the number, save to the database and send it by sms.
so i put a log file in both files and waited to the duplicate to show.
this is from a log file I made to track this issue:
Time: 2014/05/24 06:41:46 - user: 610410 - random: Going IN
Time: 2014/05/24 06:41:46 - user: 610410 - random: Going IN
Time: 2014/05/24 06:41:46 - user: 610410 - random: Going IN
Time: 2014/05/24 06:41:46 - user: 610410 - random: Going IN
Time: 2014/05/24 06:41:49 - user: 610410 - random: 853967
Time: 2014/05/24 06:41:49 - user: 610410 - random: 853967
Time: 2014/05/24 06:41:49 - user: 610410 - random: 853967
Time: 2014/05/24 06:41:49 - user: 610410 - random: 853967
what is the cause and how to solve it.
UPDATE: Code added
getRandomNumber.asmx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Script.Services;
using System.Web.Script.Serialization;
using OracleDataAccessLayer;
namespace MobileWebServices
{
[WebService(Namespace = "http://www.example.com")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class getRandomNumber : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public string sendRandomNumber(int UserNumber)
{
Logger.logError("Time: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + " - user: " + UserNumber + " - random: Going IN");
return Newtonsoft.Json.JsonConvert.SerializeObject(new getRandomNumber().sendRandomNumber(UserNumber));
}
}
}
getRandomNumber.cs
using System;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net;
using System.Text;
using System.IO;
namespace OracleDataAccessLayer
{
public class getRandomNumber : OracleDataAccessLayer.MobileDataAccess.OracleCommandLibrary
{
string sql = "";
public getRandomNumber() { }
string GeneratePasscode(int PasscodeLength)
{
string _allowedChars = "123456789";
Random randNum = new Random();
char[] chars = new char[PasscodeLength];
int allowedCharCount = _allowedChars.Length;
for (int i = 0; i < PasscodeLength; i++)
{
chars[i] = _allowedChars[(int)((_allowedChars.Length) * randNum.NextDouble())];
}
return new string(chars).PadRight(PasscodeLength, '0').ToString();
}
public string sendRandomNumber(int parUserNumber)
{
string random = "0";
string mobile="";
try
{
string randomNum = GeneratePasscode(6);
Logger.logError("Time: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + " - user: " + parUserNumber + " - random: " + randomNum);
//select the mobile number and the language
sql = "SELECT C.COUNTRY_LANG, MOBILE " +
"FROM COUNTRY_MASTER_TABLE C " +
"JOIN USER_REG_MASTER U ON " +
"C.COUNTRY_CODE = U.NATIONALITY_NO " +
"WHERE U.UNO = " + parUserNumber;
DataTable lang = Retrievedata(sql);
if (lang.Rows.Count > 0)
{
sql = "INSERT INTO SMS_SEND " +
"(SMS_ID, USER_NUMBER, SMS_DATE, RANDOM, DEVICE_TYPE) VALUES " +
"(SEQ_RANDOM.NEXTVAL, " + parUSERNumber + ", SYSDATE, " + randomNum + ", 1)";
if (ExecuteTransactions(sql) > 0)
{
mobile = lang.Rows[0].ItemArray[1].ToString();
// check the lang Arabic, Non Arabic
// if arabic convert to hex
if (lang.Rows[0].ItemArray[0].ToString() == "A")
{
messageOrg = "الرجاء استخدام الرمز " + randomNum;
Byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes(messageOrg);
StringBuilder sbBytes = new StringBuilder(stringBytes.Length * 2);
foreach (byte bb in stringBytes)
{
sbBytes.AppendFormat("%{0:X2}", bb);
}
message = sbBytes.ToString();
messageHex = message;
}
else
{
// If english do nothing
messageOrg = "Please use this code: " + randomNum;
message = "Please use this code: " + randomNum;
}
// add the message and mobile number to SMS service provider URL and create HttpWebRequest
string url = "http://www.example.com/Send.aspx?MOBILENO=" + mobile + "&MESSAGE=" + message + "&rest of prams";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
// execute request and get response back
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
smsSequence = reader.ReadToEnd();
reader.Close();
dataStream.Close();
}
// check if success get the response and check id number and insert into SMS_SENTBOX for logging
int success = 0;
if (smsSequence.Substring(0, 3) == "+OK")
//if (Int32.TryParse(smsSequence.Substring(7, smsSequence.Length - 7), out success))
{
random = randomNum;
sql = "INSERT INTO SMS_SENTBOX " +
"(SMS_SENT_SEQUENCE, USER_NUMBER, EVENT_DATE, EVENT_TIME, USER_MOBILE, EVENT_TYPE, SENT_DATE, SMS_TEXT, SMS_TEXT_DUMP)" +
"VALUES " +
"(1, " + parUserNumber + ", SYSDATE, TO_CHAR(SYSDATE, 'HHMI'), " + mobile + ", 'random', SYSDATE, '" + messageOrg + "', '" + messageHex + "')";
try
{
ExecuteTransactions(sql);
}
catch (Exception e)
{
}
}
}
}
}
catch (Exception e)
{
Logger.logError(e.ToString() + "\n");
throw e;
}
return random;
/**/
}
}
}
thankyou
From your description, I don't quite understand whether you have a single problem (the same random number is generated multiple times) or two problems (same random number and request is sent multiple times).
Anyhow, the source of your problem is described in Microsoft's documentation about the Random() constructor:
The default seed value is derived from the system clock and has finite
resolution. As a result, different Random objects that are created in
close succession by a call to the default constructor will have
identical default seed values and, therefore, will produce identical
sets of random numbers.
To fix it, create a single static instance of Random:
static Random random = new Random();
....
string GeneratePasscode(int PasscodeLength)
{
string _allowedChars = "123456789";
char[] chars = new char[PasscodeLength];
int allowedCharCount = _allowedChars.Length;
for (int i = 0; i < PasscodeLength; i++)
{
chars[i] = _allowedChars[(int)((_allowedChars.Length) * random.NextDouble())];
}
return new string(chars).PadRight(PasscodeLength, '0').ToString();
}

ASP.Net OutputCacheProvider strange behavior

I have implement a simple file-based custom OutputCacheProvider based on samples i found on the Internet.
The code follows:
using System;
using System.Configuration;
using System.IO;
using System.Web;
using System.Web.Caching;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Diagnostics;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace SimpleCachedProvider
{
public class FileCacheProvider : OutputCacheProvider {
private string _cachePath;
void WriteToFile(String filename, String contents) {
FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter w = new StreamWriter(fs, System.Text.Encoding.GetEncoding(1253));
w.BaseStream.Seek(0, SeekOrigin.Begin);
w.BaseStream.SetLength(0);
w.Write(contents);
w.Flush();
w.Close();
}
void AppendToFile(String filename, String contents) {
if (contents.ToLower().IndexOf("ss2.aspx") >= 0 || contents.ToLower().IndexOf("default.aspx") >= 0) {
FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter w = new StreamWriter(fs, System.Text.Encoding.GetEncoding(1253));
w.BaseStream.Seek(0, SeekOrigin.End);
w.Write(contents);
w.Flush();
w.Close();
}
}
private string CachePath {
get {
if (!string.IsNullOrEmpty(_cachePath))
return _cachePath;
_cachePath = ConfigurationManager.AppSettings["OutputCachePath"];
var context = HttpContext.Current;
if (context != null) {
_cachePath = context.Server.MapPath(_cachePath);
if (!_cachePath.EndsWith("\\"))
_cachePath += "\\";
}
return _cachePath;
}
}
public override object Add(string key, object entry, DateTime utcExpiry) {
var path = GetPathFromKey(key);
AppendToFile(CachePath + "info.txt", "ADD: " + key + " (" + path + ")\r\n");
if (File.Exists(path)) {
AppendToFile(CachePath + "info.txt", "ADD: " + key + " (" + path + ") already exists. Will be returned.\r\n");
return entry;
}
AppendToFile(CachePath + "info.txt", "ADD: " + key + " (" + path + ") does not exists. Will be created.\r\n");
using (var file = File.OpenWrite(path)) {
var item = new CacheItem { Expires = utcExpiry, Item = entry };
var formatter = new BinaryFormatter();
formatter.Serialize(file, item);
AppendToFile(CachePath + "info.txt", "ADD: " + key + " (" + path + ") saved to disk.\r\n");
}
return entry;
}
public override void Set(string key, object entry, DateTime utcExpiry) {
var item = new CacheItem { Expires = utcExpiry, Item = entry };
var path = GetPathFromKey(key);
AppendToFile(CachePath + "info.txt", "Set: " + key + " (" + path + ") requested.\r\n");
using (var file = File.OpenWrite(path)) {
var formatter = new BinaryFormatter();
formatter.Serialize(file, item);
AppendToFile(CachePath + "info.txt", "Set: " + key + " (" + path + "): " + utcExpiry.ToLocalTime().ToString("dd/MM/yyyy HH:mm:ss") + " saved to disk.\r\n");
}
}
public override object Get(string key) {
var path = GetPathFromKey(key);
AppendToFile(CachePath + "info.txt", "Get: Querying " + key + " (" + path + ")\r\n");
if (!File.Exists(path)) {
AppendToFile(CachePath + "info.txt", "Get: " + key + " (" + path + ") not found.\r\n");
return null;
}
CacheItem item = null;
using (var file = File.OpenRead(path)) {
var formatter = new BinaryFormatter();
item = (CacheItem)formatter.Deserialize(file);
AppendToFile(CachePath + "info.txt", "Get: " + key + " (" + path + ") retrieved.\r\n");
}
if (item == null || item.Expires <= DateTime.Now.ToUniversalTime()) {
AppendToFile(CachePath + "info.txt", "Get: " + key + " (" + path + ") deleted due to expiration.\r\n");
Remove(key);
return null;
}
AppendToFile(CachePath + "info.txt", "Get: " + key + " (" + path + ") retrieved and used\r\n");
return item.Item;
}
public override void Remove(string key) {
var path = GetPathFromKey(key);
AppendToFile(CachePath + "info.txt", "Remove: " + key + " (" + path + ") requested.\r\n");
if (File.Exists(path)) {
AppendToFile(CachePath + "info.txt", "Remove: " + key + " (" + path + ") executed.\r\n");
File.Delete(path);
}
}
private string GetPathFromKey(string key) {
return CachePath + MD5(key) + ".txt";
}
private string MD5(string s) {
MD5CryptoServiceProvider provider;
provider = new MD5CryptoServiceProvider();
byte[] bytes = Encoding.UTF8.GetBytes(s);
StringBuilder builder = new StringBuilder();
bytes = provider.ComputeHash(bytes);
foreach (byte b in bytes)
builder.Append(b.ToString("x2").ToLower());
return builder.ToString();
}
}
}
I have then created an .aspx with the header
<%# OutputCache Duration="3600" Location="Server" VaryByParam="*" %>
I have changed the default output cache provider to my web.config to mine.
The strange behavior is that the page is not cached. Instead this is a sample output from my debugging information. It seems that:
The page is retrieved from tha cache and sent back to ASP.Net
Right after that ASP.Net calls the Remove() method to my page
Finally ASP.Net calls Set() and the page is updated - no effective caching
Get: Querying a2/ss2.aspx (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\7394fd15241e5b7f5c437ddf28dcd0e5.txt)
Get: a2/ss2.aspx (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\7394fd15241e5b7f5c437ddf28dcd0e5.txt) retrieved.
Get: a2/ss2.aspx (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\7394fd15241e5b7f5c437ddf28dcd0e5.txt) retrieved and used
Get: Querying a2/ss2.aspxHQFCNmycustom2VDE (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\3e72454ab3f36e4cfe3964e5063be622.txt)
Get: a2/ss2.aspxHQFCNmycustom2VDE (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\3e72454ab3f36e4cfe3964e5063be622.txt) retrieved.
Get: a2/ss2.aspxHQFCNmycustom2VDE (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\3e72454ab3f36e4cfe3964e5063be622.txt) retrieved and used
Remove: a2/ss2.aspxHQFCNmycustom2VDE (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\3e72454ab3f36e4cfe3964e5063be622.txt) requested.
Remove: a2/ss2.aspxHQFCNmycustom2VDE (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\3e72454ab3f36e4cfe3964e5063be622.txt) executed.
ADD: a2/ss2.aspx (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\7394fd15241e5b7f5c437ddf28dcd0e5.txt)
ADD: a2/ss2.aspx (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\7394fd15241e5b7f5c437ddf28dcd0e5.txt) already exists. Will be returned.
Set: a2/ss2.aspxHQFCNmycustom2VDE (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\3e72454ab3f36e4cfe3964e5063be622.txt) requested.
Set: a2/ss2.aspxHQFCNmycustom2VDE (C:\eShopKey\ASP.Net\Shops\myshoe_dev\Cache\3e72454ab3f36e4cfe3964e5063be622.txt): 30/05/2012 15:07:27 saved to disk.
So my questions:
Why ASP.Net keeps invalidating my page?
When Remove() and Set() methods are called by ASP.Net? I have not found any info regarding that.
If i rename the page and use this variation caching works! This is totally weird.
Note that if i use the default ASP.Net outputcacheprovider caching works as expected.
I found what is going on but unable to fix it:
Let's say i open the page: http://www.mydomain.com/mypage.aspx?param1=1
ASP.Net sends 2 consecutive GET requests to my OutputCacheProvider:
one for the page mypage.aspx
another for the same page but with the querystring parameters attached
It seems to me that the first request is somehow related with the second one, like a header.
As soon as i call consecutively the same page, with the same querystring, caching working as expected.
If i call next the page: http://www.mydomain.com/mypage.aspx?param1=2
then the same, 2 step GET sequence, is initialized. The ASP.Net sends 2 GET requests, one for the page without parameters and one with parameters.
The first GET request (for the page without parameters) is then found on the cache and returned back to ASP.Net. But somehow is unrelated with the second one. It is related to the first variation of the call (param1=1).
So, nevertheless if the second request has been cached before, ASP.Net thinks that the cached page is invalid and ask again for add / set.
To summarize it seems that you can have just one variation of the page to the cache at a given moment. All previous cahed variations will be invalidated as the page will be called again with other parameters.
There is no way to check what the first GET request is related to as ASP.NET uses the same key to retrieve it.
So my new questions:
Why ASP.Net sends 2 requests for every page to the custom output cache provider? Does anybody knows?
How i can overcome this strange behavior?
Is the AspNetInternalProvider has the same behavior?
I found the solution! The problem was on Add method. It has to be written on all providers like below:
public override object Add(string key, object entry, DateTime utcExpiry) {
String vKey = TransformKey(key);
object res = Get(key);
if (res == null) {
Set(key, entry, utcExpiry);
return entry;
}
return res;
}
The TransformKey method just returns a safe string (string without bad characters) based on key (for example the MD5 hash of the key). Look for an implementation on my first posted code.
the first request returns an object System.Web.Caching.CachedVary, and second request returns System.Web.Caching.OutputCacheEntry. According to the name of object, the first one is for OutputCache, and the second one is for the data of page.
if you have any questions, pls send email to shengzhengshan#hotmail.com
Hope it can help you!
Amir Sheng

asp.net amazon itemsearch

I'm using visual studio 2008 and trying to do API itemsearch like books or something.
I am using just accessKeyId, but when I click my "search" button to search books, then comes signature error.
Do I need to use secretKeyID also?
I just created new ASP.Net web site in visual studio Or I have to use AWS SDK for.Net package?
Can somebody please give a good advice.
Thanks!
Signature error means you did not create a request signature properly. You should use the SprightlySoft AWS Component for .NET. It's free and it supports the Product Advertising API. Get it at http://sprightlysoft.com/. The AWS SDK for.NET does not work with the Product Advertising API.
Here is an example of calling ItemSearch with the SprightlySoft component.
//Product Advertising API, ItemSearch: http://docs.amazonwebservices.com/AWSECommerceService/2010-10-01/DG/ItemSearch.html
SprightlySoftAWS.REST MyREST = new SprightlySoftAWS.REST();
String RequestURL;
RequestURL = "https://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService&Operation=ItemSearch&Version=2010-10-01";
RequestURL += "&AWSAccessKeyId=" + System.Uri.EscapeDataString(TextBoxAWSAccessKeyId.Text) + "&SignatureVersion=2&SignatureMethod=HmacSHA256&Timestamp=" + Uri.EscapeDataString(DateTime.UtcNow.ToString("yyyy-MM-dd\\THH:mm:ss.fff\\Z"));
RequestURL += "&Actor=" + System.Uri.EscapeDataString("Tom Cruise");
RequestURL += "&SearchIndex=DVD";
RequestURL += "&ResponseGroup=" + System.Uri.EscapeDataString("ItemAttributes,Reviews");
RequestURL += "&Sort=salesrank";
RequestURL += "&ItemPage=1";
String RequestMethod;
RequestMethod = "GET";
String SignatureValue;
SignatureValue = MyREST.GetSignatureVersion2Value(RequestURL, RequestMethod, "", TextBoxAWSSecretAccessKey.Text);
RequestURL += "&Signature=" + System.Uri.EscapeDataString(SignatureValue);
Boolean RetBool;
RetBool = MyREST.MakeRequest(RequestURL, RequestMethod, null);
System.Diagnostics.Debug.Print(MyREST.LogData);
String ResponseMessage = "";
if (RetBool == true)
{
System.Xml.XmlDocument MyXmlDocument;
System.Xml.XmlNamespaceManager MyXmlNamespaceManager;
System.Xml.XmlNode MyXmlNode;
System.Xml.XmlNodeList MyXmlNodeList;
MyXmlDocument = new System.Xml.XmlDocument();
MyXmlDocument.LoadXml(MyREST.ResponseString);
MyXmlNamespaceManager = new System.Xml.XmlNamespaceManager(MyXmlDocument.NameTable);
MyXmlNamespaceManager.AddNamespace("amz", "http://webservices.amazon.com/AWSECommerceService/2010-10-01");
MyXmlNodeList = MyXmlDocument.SelectNodes("amz:ItemSearchResponse/amz:Items/amz:Item", MyXmlNamespaceManager);
if (MyXmlNodeList.Count == 0)
{
ResponseMessage = "No items exist.";
}
else
{
foreach (System.Xml.XmlNode ItemXmlNode in MyXmlNodeList)
{
MyXmlNode = ItemXmlNode.SelectSingleNode("amz:ItemAttributes/amz:Title", MyXmlNamespaceManager);
ResponseMessage += "Title = " + MyXmlNode.InnerText;
MyXmlNode = ItemXmlNode.SelectSingleNode("amz:ItemAttributes/amz:ListPrice/amz:FormattedPrice", MyXmlNamespaceManager);
ResponseMessage += " ListPrice = " + MyXmlNode.InnerText;
ResponseMessage += Environment.NewLine;
}
}
MessageBox.Show(ResponseMessage);
}
else
{
MessageBox.Show(MyREST.ResponseStringFormatted);
}

Resources