Asp.net Routing not working properly - asp.net

I have written the following inside my RegisterRoutes() in Global.asax in webforms application.
I have an xml file called CacheInfo.xml that stores the details of cached pages.The default page has an entry in the xml called EnDefaultPage, which contains two child nodes.
The child node LastUpdationTimeStamp stores, last updation timestamp (unix timestamp in seconds ) of the cache for Default page.
The child node ExpiryTimestamp stores the timestamp at which the cache will be expired.So if the expiry timestamp is greater than lastupdation timestamp, the file from Cache will be loaded (Default.html).Currently the script is working, but it is not routing to the Default.html although the conditional block that defines the route is being executed.I couldn't find the exact reason behind the issue.Can anybody suggest me a fix.All the other routes are working perfectly.
My code is attached below.
ublic void RegisterRoutes(RouteCollection routes)
{
string relPath = "~/CacheInfo.xml";
string absPath = Server.MapPath(relPath);
XmlDocument xdoc = new XmlDocument();//xml doc used for xml parsing
xdoc.Load(
absPath
);//loading XML in xml doc
string nodeName="", nodeVal="",upStamp="0",expiry="0";
int iUpStamp,iExpiry;
upStamp = xdoc.GetElementsByTagName("EnDefaultPage")[0].SelectSingleNode("LastUpdationTimeStamp").InnerText;
expiry = xdoc.GetElementsByTagName("EnDefaultPage")[0].SelectSingleNode("ExpiryTimeStamp").InnerText;
iUpStamp = Convert.ToInt32(upStamp);
iExpiry = Convert.ToInt32(expiry);
if(!String.IsNullOrEmpty(upStamp)) {
if (iExpiry > iUpStamp)
{
System.Diagnostics.Debug.WriteLine("stamp is " + upStamp + " Expiry is " + expiry);
// routes.MapPageRoute("EnHome1", "", "~/en/DefaultCache.aspx");
routes.MapPageRoute("EHome", "en/", "~/en/Default.html");
//this routing is not working
}
else
{
}
}
routes.MapPageRoute("GArticle", "Gallery/{slug}", "~/Gallery/Article.aspx");
routes.MapPageRoute("GCategory", "Gallery/Categories/{slug}", "~/Gallery/Categories.aspx");
routes.MapPageRoute("GSlideShow", "Gallery/{slug}/{id}", "~/Gallery/SlideShow.aspx");
routes.MapPageRoute("Article", "en/{slug}", "~/english/Article.aspx");
routes.MapPageRoute("Category", "en/Categories/{slug}", "~/english/Categories.aspx");
routes.MapPageRoute("enFeed", "en/category/english/{slug}/feed", "~/en/feed.aspx");
routes.MapPageRoute("teFeed", "te/category/telugu/{slug}/feed", "~/te/feed.aspx");
routes.MapPageRoute("Tags", "en/Tags/{tag}", "~/english/Tags.aspx");
routes.MapPageRoute("tArticleHtml", "te/{slug}.html", "~/telugu/Article.aspx");
routes.MapPageRoute("tArticle", "te/{slug}", "~/telugu/Article.aspx");
routes.MapPageRoute("tCategoryHtml", "te/Categories/{slug}.html", "~/telugu/Categories.aspx");
routes.MapPageRoute("tCategory", "te/Categories/{slug}", "~/telugu/Categories.aspx");
routes.MapPageRoute("tTagsHtml", "te/Tags/{tag}.html", "~/telugu/Tags.aspx");
routes.MapPageRoute("tTags", "te/Tags/{tag}", "~/telugu/Tags.aspx");
}
}

If I read your intent correctly, you want the user to be directed to default any time their access is expired. If so, you can't get there from here.
RegisterRoutes is used to register routes as the application starts up.The last 3 words are the clue as to why certain logic will not work later in the application.
Now to your RegisterRoutes. Here is the logic.
Get expiration date
Get timestamp
If the expiration date is greater than last updated, when the application starts, route the user to default
If you truly mean "at startup determine whether to route every page that can be expired to default, every time" then you have the correct logic and it is working as expected. The fact you asked the question says that is not your intent. You want a decision made on a page access by page access basis. If I am correct, you can't do it in RegisterRoutes. You will have to implement the "caching logic" elsewhere.
My suggestion, rather than building this by hand, is look into software that handles caching.

Related

.Net Core 3.1 Razor Pages : autoredirect to culture

I try to accomplish a similar behaviour with MS Docs.
For example, if you visit https://learn.microsoft.com/, you will be redirected to your culture, in my case I'm being redirected automatically to https://learn.microsoft.com/en-gb/.
Same goes for inner pages if you access them without the culture in the URL.
For instance, by accessing:
https://learn.microsoft.com/aspnet/core/razor-pages/?view=aspnetcore-3.1&tabs=visual-studio
it will be automatically redirect you to:
https://learn.microsoft.com/en-gb/aspnet/core/razor-pages/?view=aspnetcore-3.1&tabs=visual-studio
I have a small demo app where I conduct my localisation experiment for .NET Core 3.1 and Razor Pages here.
I have set options.Conventions here, and I have created CustomCultureRouteRouteModelConvention class here, but I'm fairly novice with .NET Core and I'm kind of stuck on how to implement the above-described functionality.
Thank you all in advance!
You should use existing Rewriting Middleware to do redirects: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-3.1
In the simplest form, you can tell rewrite middleware to redirect if it does not see a locale pattern at the beginning of the URL path, maybe
new RewriteOptions() .AddRedirect("^([a-z]{2}-[a-z]{2})", "en-US/$1")
(regex not tested) or do full redirect class with more detailed rules when and to what locale you want to redirect. Example in that aspnet document references RedirectImageRequest which you can use to get an understanding of how custom redirect rules works. Adapting to your case as a proof of concept, I reused most of the logic in your existing RedirectUnsupportedCulture:
public class RedirectUnsupportedCultures : IRule
{
private readonly string _extension;
private readonly PathString _newPath;
private IList<CultureInfo> _cultureItems;
private string _cultureRouteKey;
public RedirectUnsupportedCultures(IOptions<RequestLocalizationOptions> options)
{
RouteDataRequestCultureProvider provider = options.Value.RequestCultureProviders
.OfType<RouteDataRequestCultureProvider>()
.First();
_cultureItems = options.Value.SupportedUICultures;
_cultureRouteKey = provider.RouteDataStringKey;
}
public void ApplyRule(RewriteContext rewriteContext)
{
// do not redirect static assets and do not redirect from a controller that is meant to set the locale
// similar to how you would not restrict a guest user from login form on public site.
if (rewriteContext.HttpContext.Request.Path.Value.EndsWith(".ico") ||
rewriteContext.HttpContext.Request.Path.Value.Contains("change-culture"))
{
return;
}
IRequestCultureFeature cultureFeature = rewriteContext.HttpContext.Features.Get<IRequestCultureFeature>();
string actualCulture = cultureFeature?.RequestCulture.Culture.Name;
string requestedCulture = rewriteContext.HttpContext.GetRouteValue(_cultureRouteKey)?.ToString();
// Here you can add more rules to redirect based on maybe cookie setting, or even language options saved in database user profile
if(string.IsNullOrEmpty(requestedCulture) || _cultureItems.All(x => x.Name != requestedCulture)
&& !string.Equals(requestedCulture, actualCulture, StringComparison.OrdinalIgnoreCase))
{
string localizedPath = $"/{actualCulture}{rewriteContext.HttpContext.Request.Path.Value}";
HttpResponse response = rewriteContext.HttpContext.Response;
response.StatusCode = StatusCodes.Status301MovedPermanently;
rewriteContext.Result = RuleResult.EndResponse;
// preserve query part parameters of the URL (?parameters) if there were any
response.Headers[HeaderNames.Location] =
localizedPath + rewriteContext.HttpContext.Request.QueryString;
}
}
and registered it in Startup.cs with
// Attempt to make auto-redirect to culture if it is not exist in the url
RewriteOptions rewriter = new RewriteOptions();
rewriter.Add(new RedirectUnsupportedCultures(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>()));
app.UseRewriter(rewriter);
Improvement:
After using the above code I bumped on a bug that in case the culture is not supported by the application, the redirection will end up with infinite culture paths. For example, if I support the cultures en (default) and gr, if instead of either /en/foobar or /gr/foobar I would write /fr/foobar, I would end up getting /en/fr/foobar then /en/en/fr/foobar and etc.
I added private readonly LinkGenerator _linkGenerator; to the class, which I initialise it in the constructor. I removed that line string localizedPath = $"/{actualCulture}{rewriteContext.HttpContext.Request.Path.Value}"; and the code after that line looks like this:
rewriteContext.HttpContext.GetRouteData().Values[_cultureRouteKey] = actualCulture;
HttpResponse response = rewriteContext.HttpContext.Response;
response.StatusCode = StatusCodes.Status301MovedPermanently;
rewriteContext.Result = RuleResult.EndResponse;
// preserve query part parameters of the URL (?parameters) if there were any
response.Headers[HeaderNames.Location] =
_linkGenerator.GetPathByAction(
rewriteContext.HttpContext,
values: rewriteContext.HttpContext.GetRouteData().Values
)
+ rewriteContext.HttpContext.Request.QueryString;
As decribed in Microsoft docs localization middleware; each the localization request initializes a list of RequestCultureProvider and is enumerated by the below order :
QueryStringRequestCultureProvider : e.g. http://localhost:1234/Index?culture=en
CookieRequestCultureProvider : Looks for the culture cookie, and it will be null if you haven't set it manually.
AcceptLanguageHeaderRequestCultureProvider : This one depends on the browsers cultures adn this is what you need to look for.
To make sure how it works, delete the culture cookie and change the browser language preferences by moving the desired language to the top, you will see that the language is selected according to the browser preferences.

CreateEnvelopeFromTemplates - Guid should contain 32 digits with 4 dashes

I am attempting to create a DocuSign envelope from a template document using the CreateEnvelopeFromTemplates method, available within their v3 SOAP API web service. This is being instantiated from a asp.NET v4.0 web site.
Upon calling the method armed with the required parameter objects being passed in. I am recieving an exception from the web service, basically telling me that the Template ID is not a valid GUID.
669393: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
Line 14889:
Line 14890: public DocuSignDSAPI.EnvelopeStatus CreateEnvelopeFromTemplates(DocuSignDSAPI.TemplateReference[] TemplateReferences, DocuSignDSAPI.Recipient[] Recipients, DocuSignDSAPI.EnvelopeInformation EnvelopeInformation, bool ActivateEnvelope) {
Line 14891: return base.Channel.CreateEnvelopeFromTemplates(TemplateReferences, Recipients, EnvelopeInformation, ActivateEnvelope);
Line 14892: }
Line 14893:
The template reference, a guid. Must be specified as the "Template" string property against TemplateReference object. This is then added to a dynamic array of TemplateReferences, which is one of the input parameters of the CreateEnvelopeFromTemplates method.
Actual template GUID: f37b4d64-54e3-4723-a6f1-a4120f0e9695
I am building up my template reference object using the following function that i wrote to try and make the functionality reusable:
Private Function GetTemplateReference(ByVal TemplateID As String) As TemplateReference
Dim templateReference As New TemplateReference
Dim guidTemplateID As Guid
With TemplateReference
.TemplateLocation = TemplateLocationCode.Server
If Guid.TryParse(TemplateID, guidTemplateID) Then
.Template = guidTemplateID.ToString
End If
End With
Return TemplateReference
End Function
The TemplateID is being passed in from a appSetting configuration value at the time of the TemplateReferences array instantiation like so...
templateReferences = New TemplateReference() {GetTemplateReference(ConfigurationManager.AppSettings("DocuSignTemplate_Reference"))}
recipients = New Recipient() {AddRecipient("myself#work.email", "My Name")}
envelopeInformation = CreateEnvelopeInformation()
envelopeStatus = client.CreateEnvelopeFromTemplates(templateReferences, recipients, envelopeInformation, True)
As you can see from my GetTemplateReference function I am also parsing the GUID before setting it back as a string so i know its valid. The template is managed and stored at the DocuSign end, hence specifying the document location.
I am referring to their own documentation:
CreateEnvelopeFromTemplates
Why oh why is the method not liking my Template ID? I can successfully use their REST API to call the same method, using their own code samples. Worst case I can make use of this but would rather interact with the web service as I would need to construct all the relevent requests in either XML or JSON.
I would really appreciate if someone could perhaps shed some light on this problem.
Thanks for taking the time to read my question!
Andrew might be spot on with the AccountId mention - are you setting the AccountId in the envelope information object? Also, have you seen the DocuSign SOAP SDK up on Github? That has 5 sample SOAP projects including one MS.NET project. The .NET project is in C# not Visual Basic, but still I think it will be helpful to you. Check out the SOAP SDK here:
https://github.com/docusign/DocuSign-eSignature-SDK
For instance, here is the test function for the CreateEnvelopeFromTemplates() function:
public void CreateEnvelopeFromTemplatesTest()
{
// Construct all the recipient information
DocuSignWeb.Recipient[] recipients = HeartbeatTests.CreateOneSigner();
DocuSignWeb.TemplateReferenceRoleAssignment[] finalRoleAssignments = new DocuSignWeb.TemplateReferenceRoleAssignment[1];
finalRoleAssignments[0] = new DocuSignWeb.TemplateReferenceRoleAssignment();
finalRoleAssignments[0].RoleName = recipients[0].RoleName;
finalRoleAssignments[0].RecipientID = recipients[0].ID;
// Use a server-side template -- you could make more than one of these
DocuSignWeb.TemplateReference templateReference = new DocuSignWeb.TemplateReference();
templateReference.TemplateLocation = DocuSignWeb.TemplateLocationCode.Server;
// TODO: replace with template ID from your account
templateReference.Template = "server template ID";
templateReference.RoleAssignments = finalRoleAssignments;
// Construct the envelope information
DocuSignWeb.EnvelopeInformation envelopeInfo = new DocuSignWeb.EnvelopeInformation();
envelopeInfo.AccountId = _accountId;
envelopeInfo.Subject = "create envelope from templates test";
envelopeInfo.EmailBlurb = "testing docusign creation services";
// Create draft with all the template information
DocuSignWeb.EnvelopeStatus status = _apiClient.CreateEnvelopeFromTemplates(new DocuSignWeb.TemplateReference[] { templateReference },
recipients, envelopeInfo, false);
// Confirm that the envelope has been assigned an ID
Assert.IsNotNullOrEmpty(status.EnvelopeID);
Console.WriteLine("Status for envelope {0} is {1}", status.EnvelopeID, status.Status);
}
This code calls other sample functions in the SDK which I have not included, but hopefully this helps shed some light on what you're doing wrong...
This problem arises when you don't set up the field AccountId. This field can be retrieved from your account. In Docusign's console go to Preferences / API and look here
Where to find AccountID Guid in Docusign's Console
Use API Account ID (which is in GUID format) and you should be OK.

Session, Cache OR Cookies which one to use to retain Search Criteria of User? (Posted With Case Study)

I am developing a Web application which is based on ASP.NET 4.0, JQUERY, AJAX and Javascript. I have a particular search page in which a user can search via multiple factors i.e. either by Date, Name, Code, Category etc.
For e.g.
A) In a SearchProducts form, user can search a product via its unique Number OR Name OR Start Date/End Date OR Category OR etc etc.
B) User can search by either one or all of the parameters which a standard search form should be able to do.
C) If user searches via Start Date and End Date say 1st Dec 2012 to 31st Dec 2012 so for example my Search Results consist of 4 Products i.e. 4 products are purchased from 1st Dec to 31st Dec
D) Results are displayed in the grid and by clicking on the Product Number its redirecting to its View page (selected Product Specific full details) with ProductID via Query string.
E) I have a requirement which enables the user to retain search results which he/she has searched via Back To Search button in View page (selected Product Specific full details) page.
Now, What I have planned is as follows:
1) When a user submits on the Search then I want to store the refference of Search Paramters i.e Date, Name, Category etc which user has entered.
2) I will set a value in query string to differentiate normal request and request Via Back to Search button.
3) code in Search Page:
if (!(IsPostBack))
{
string tempRequestMode = string.Empty;
if (Request.QueryString["requestMode"] != null)
{
tempRequestMode = Request.QueryString["requestMode"].ToString();
if (tempRequestMode == "searchResults")
{
//RestoreValues();
//Fetch results from the database again based on above results
}
}
}
Now, My question is:
I wanted to use ASP.NET Cache for this purpose:
Advantages: its expiration and dependencies
Disadvantages: its has the application scope i.e. its not per user wise as Session is.
Second option is session:
Advantages: its per user wise.
Disadvantages: Session is more memory intensive.
I am confused that what Should I use. Is there any other option to use as Search Criteria is different for different users so want user wise maintenance of data.
You can write all search criteria to QueryString.
When a User clicks the Search Button, run this Javascript:
CLIENT-SIDE
<script type="text/javascript">
var url = "Invoices.aspx?type=__type__&status=__status__&order=__order__";
var type= $("#<%= drpType.ClientID%>").val(); // Type
var status = $("#<%= drpStatus.ClientID %>").val(); // Status Parameter
var order = $("#<%= drpOrder.ClientID %>").val(); // order Parameter
window.location = url.replace("__type__",type).replace("__status__",status).replace("__order__",order).replace(");
</script>
SERVER-SIDE
protected void Page_Load(object cart, EventArgs curt)
{
_type = Request.QueryString["type"];
if (string.IsNullOrEmpty(_type))
_type = Enums.InvoiceUserTypes.RS.ToString(); //Default
_status = Request.QueryString["status"];
if (string.IsNullOrEmpty(_status)) _status = "ALL"; //Default
_order= Request.QueryString["order"];
if (string.IsNullOrEmpty(_order)) _order = "date"; //Default
drpStatus.Value = _status;
drpType.Value = _type;
drpOrder.Value = _order;
RunReport();
}
When user click Back button . Search parameters will be on the URL
I think the best approach to this case is to redo the search using the stored filters once the user gets back to the search page. Any other approaches will bring you a big drawback.
Caches Expire and if you use the default implementation they won't allow your app to scale to multiple machines since they are local.
Using sessions is a bad idea too because they will eat your resources AND won't allow you to scale too.
If you must store the results you should store them serialized (LOB pattern) in a database or another network accessible resource so you could retrieve them in any application server.

asp.net membership, notify administrators when account about to expire

I have a requirement that a certain email distribution list should be notified every so often (still to be determined) about user accounts that are nearing expiration.
I'm wondering the best way to achieve this, I know its generally a bad idea to spawn another thread within asp.net to handle this type of thing, so I'm thinking maybe a simple service is the way to go but for something so small this seems like it might be slightly overkill.
Ideally I'd like something that doesnt require much babysitting (eg. checking service is running).
I have also suggested having a page in the site with this type of information but it is likely that it could be a few days before this is checked. We also cannot let users extend their own expiration date.
Are there any other viable options.
The best suitable method to work on it according to is
create a application which will select list of all users whose account expiry date is nearby (eg. 10 days from today) as per your requirement.
This application will be scheduled as an daily execution (you will create an exe with log file to display errors raised and total number of emails sent in one execution.)
This application will fetch all the records based on criteria and send the emails to all yours using the basic HTML template. and once the email is sent, you will update a column (notificationFlag) in your database as 1 if you have sent is once in last 10 days. else by default it will be 0
you can schedule the exe by the end of the day at 12:10 am (just incase your database server and webserver is not matching in time) every day. .
This is something I've done which is similar to Prescott's comment on your answer.
I have a website with an administrative page that reports on a bunch of expiration dates.
This page also accepts a QueryString parameter SEND_EMAILS, so anytime an administrative user of the site passes the QueryString parameter SEND_EMAILS=true a bunch of emails go out to all the users that are expiring.
Then I just added a windows scheduled task to run daily and load the page with the SEND_EMAILS=true parameter.
This was the simple code I used to issue the webrequest from the console in the scheduled task:
namespace CmdLoadWebsite
{
class Program
{
static void Main(string[] args)
{
string url = "http://default/site/";
if (args.Length > 0)
{
url = args[0];
}
Console.WriteLine(GetWebResult(url));
}
public static string GetWebResult(string url)
{
byte[] buff = new byte[8192];
StringBuilder sb = new StringBuilder();
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
Stream webStream = response.GetResponseStream();
int count = 0;
string webString;
do
{
count = webStream.Read(buff, 0, buff.Length);
if (count != 0)
{
webString = Encoding.ASCII.GetString(buff, 0, count);
sb.Append(webString);
}
}
while (count > 0);
return(sb.ToString());
}
}
}

Passing flash variables to asp.net

I don't know much about Flash but we are working on a site that has a flash form and when the users pick an option, like selecting a value from a drop down list, we need the value to be passed to asp.net server-side code. What's the easiest way to do this?
Flash can invoke server side service. So use GET or POST to pass data
You could explore these options:
1) Communicate between the SWF and the containing page through JavaScript
2) Communicate via asp.net webservices from the SWF directly to the webservice.
3) Not sure but could probably do a POST to a processing aspx page?
HTH
I think a good option is to use the XML class so consider this:
var xmlRequest = new XML();
xmlRequest.onLoad = parseXMLResponse;
xmlRequest.load("http://yourpathtoyourserver/file.aspx?listselectedvalue=something");
function parseXMLRequest(loaded)
{
trace("hi");
}
You can also have the page give you data back this way so it's not just one way communication.
Assuming you are using Action Script 2.
Read the important notes at the bottom of each codes pertain to sending and retrieving data from flash to .net page. Explanation of the code is in the comment inside the code.
Flash Part (Action Script 2)
//function to send collected form data to asp.net page
//use other control/button to call this function
//important: in order for the 'onLoad' event to work correctly, this function has to be 'Void'
function sendForm():Void
{
//create LoadVars object
var lv_in:LoadVars = new LoadVars();
var lv_out:LoadVars = new LoadVars();
//set onLoad event
lv_in.onLoad = function(success:Boolean)
{
//if success, meaning data has received from .net page, run this code
if (success)
{
//lv_in.status is use to get the posted data from .Net page
statusMsg.text = "Thank you for filling up the form!" + lv_in.status;
}
//if fail, run this code
else
{
statusMsg.text = "The form you are trying to fill up has an error!";
}
}
//this is the collected data from the form
lv_out.userName = txtUserName.text;
lv_out.userAddress = txtUserAddress.text;
lv_out.userBirthday = txtUserBirthday.text;
//begin invoke .net page
lv_out.sendAndLoad("ProcessDataForm.aspx", lv_in, "POST");
}
Important note:
The function that contain onLoad event, in this case sendForm function, has to be Void function, meaning it's not returning value. If this function return value, what happen is the function will be executed all the way without waiting for the returned data from .net page, thus the onLoad event will not be set properly.
.Net Part
public void ProcessData
{
//process the data here
Response.Write("status=processed&");
}
Important note:
To send data/message back to flash, you can use Response.Write. However, if you want Action Script to parse the posted message/data from .Net page keep in mind you have to include & symbol at the end of the message. When parsing data/message, Action Script will stop at & symbol, thus leave the rest of the message alone and only get the message under sent variable.

Resources