asp.net web service executed more than one time - asp.net

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();
}

Related

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;

How can I make sure .asmx JSON results are using Newtonsoft.JSON?

I have asked a couple of questions about serializing dictionaries and I realized I may not even be using Newtonsoft.JSON in my .ASMX responses!
I have a JSON-emitting webservice class in an .asmx file:
[WebService(Namespace = "www.???.com")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class ApplicationService : JSONWebServiceBase
{
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public DateTime GetX()
{
return DateTime.Now;
}
}
To check my JSON, I returned a DateTime property, and using simon_weaver's test this date showed up on the client as
{"\/Date(1355627201572)\/"}
instead of
{"2012-12-15T19:07:03.5247384-08:00"}
which tells me the Microsoft serializer is being used and not Newtonsoft.JSON. How do I tell ASP.NET I want to use Newtonsoft?
Check following may work for your
var d = new Date(1245398693390);
var formattedDate = d.getDate() + "-" + (d.getMonth() + 1) + "-" + d.getFullYear();
var hours = (d.getHours() < 10) ? "0" + d.getHours() : d.getHours();
var minutes = (d.getMinutes() < 10) ? "0" + d.getMinutes() : d.getMinutes();
var formattedTime = hours + ":" + minutes;formattedDate = formattedDate + " " + formattedTime;

How use custom class in WebMatrix v2?

I do first steps in the ASP.NET and I've a issue with classes. I would like to create a new custom class to support sessions and collect information about the number of users on my website.
I've created a class in file MySession.cs, which has been put in the dir called "App_data" by WebMatrix.
When I try to use this class in .cshtml file, it throws me information it couldn't found that class.
I found in the Web, the class should be placed in App_Code, so I've done it. However, in this moment it shows me an error that classes like "Request" couldn't been found.
How to use custom class in WebMatrix?
My c# code from .cshtml file looks like:
#{
MySession session = new MySession(60);
session.start();
var db = Database.Open("studia");
var data = db.Query("SELECT COUNT(*) as total FROM sessions");
}
and class file looks like:
using System;
using System.Collections.Generic;
using System.Web;
using System.Security.Cryptography;
using System.Data;
using System.Data.SqlClient;
/// <summary>
/// Summary description for sesss
/// </summary>
public class MySession
{
private String _session_id;
private int _session_time;
public MySession(int session_time = 60)
{
_session_time = session_time;
using (MD5 md5Hash = MD5.Create())
{
_session_id = (Request.Cookies["session_id"] != null) ? Server.HtmlEncode(Request.Cookies["sesion_id"].Value) : GetMd5Hash(md5Hash, DateTime.Now);
}
cleanup();
}
public bool isLogged()
{
if (Request.Cookies["session_id"] != null)
{
return true;
}
return false;
}
public void start(string username)
{
DateTime now = DateTime.Now;
var db = Database.Open("studia");
if (isLogged())
{
db.Query("UPDATE sessions SET start_time = " + now + " WHERE session_id = " + _session_id);
}
else
{
db.Query("INSERT INTO sessions (id, start_time, username) VALUES ('" + _session_id + "', '" + now + "', '" + username + "'");
}
HttpCookie session_cookie = new HttpCookie("session_id");
session_cookie.Value = DateTime.Now;
session_cookie.Expires = DateTime.Now.AddSeconds(_session_time);
Response.Cookies.Add(aCookie);
}
public void cleanup()
{
var db = Database.Open("studia");
db.Query("DELETE FROM sessions WHERE start_time < " + (DateTime.Now - _session_time));
}
static string GetMd5Hash(MD5 md5Hash, string input)
{
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
// Verify a hash against a string.
static bool VerifyMd5Hash(MD5 md5Hash, string input, string hash)
{
// Hash the input.
string hashOfInput = GetMd5Hash(md5Hash, input);
// Create a StringComparer an compare the hashes.
StringComparer comparer = StringComparer.OrdinalIgnoreCase;
if (0 == comparer.Compare(hashOfInput, hash))
{
return true;
}
else
{
return false;
}
}
}
If you want to refer to the Request object in a class (as opposed to from within a page file) you need to use HttpContext.Current e.g.
public bool isLogged()
{
return HttpContext.Current.Request.Cookies["session_id"] != null;
}

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

UnitTest Method for AJAX JSON Calls to an API

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.

Resources