I'm developing a website in ASP.Net 4. One of the requirements is to log search queries that people use to find our website. So, assuming that a URL parameter named "q" is present in Referrer, I've written the following code in my MasterPage's Page_Load:
if (!CookieHelper.HasCookie("mywebsite")) CookieHelper.CreateSearchCookie();
And my CookieHelper class is like this:
public class CookieHelper
{
public static void CreateSearchCookie()
{
if (HttpContext.Current.Request.UrlReferrer != null)
{
if (HttpContext.Current.Request.UrlReferrer.Query != null)
{
string q = HttpUtility.ParseQueryString(HttpContext.Current.Request.UrlReferrer.Query).Get("q");
if (!string.IsNullOrEmpty(q))
{
HttpCookie adcookie = new HttpCookie("mywebsite");
adcookie.Value = q;
adcookie.Expires = DateTime.Now.AddYears(1);
HttpContext.Current.Response.Cookies.Add(adcookie);
}
}
}
}
public static bool HasCookie(string cookiename)
{
return (HttpContext.Current.Request.Cookies[cookiename] != null);
}
}
It seems ok at the first glance. I created a page to mimic a link from Google and worked like a charm. But it doesn't work on the host server. The reason is that when you search blah blah you see something like www.google.com/?q=blah+blah in your browser address bar. You expect clicking on your link in the results, will redirect to your site and you can grab the "q" parameter. But ,unfortunately, it is not true! Google, first redirects you to an address like:
http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CCgQFjAA&url=http%3A%2F%2Fwww.mywebsite.com%2F&ei=cks5Uof4G-aX0QXKhIGoCA&usg=AFQjCNEdmmYFpeRRRBiT_MGH5a1x9wUUlg&bvm=bv.52288139,d.d2k&cad=rja
and this will redirect to your website. As you can see the "q" parameter is empty this time! And my code gets an empty string and actually doesn't create the cookie (or whatever).
I need to know if there is a way to solve this problem and get the real "q" value. The real search term user typed to find my website. Does anybody know how to solve this?
Google stopped passing the search keyword:
http://www.searchenginepeople.com/blog/what-googles-keyword-data-grab-means-and-five-ways-around-it.html
Related
I am working on a cefsharp based browser and i am trying to implement a search engine into the browser, but the code I have tried docent work, it doesn't really have any errors but when i star the project and type something i the text field nothing happens and it dosent load the search engine i entered into the code, the only time the textbox loads anything is when a url is typed.
This is the code used in the browser that docent work
private void LoadUrl(string url)
{
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
{
WebUI.Load(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + WebUtility.HtmlEncode(url);
WebUI.Load(searchUrl);
}
}
i have also tried
void LoadURl(String url)
{
if (url.StartsWith("http"))
{
WebUI.Load(url);
}
else
{
WebUI.Load(url);
}
}
i was also suggested to try
private void LoadUrl(string url)
{
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
{
WebUI.LoadUrl(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + Uri.EscapeDataString(url);
WebUI.LoadUrl(searchUrl);
}
}
We have here really few Information on how your code works. But what I notice is that you use WebUtility.HtmlEncode for the search query. WebUtility has also a WebUtility.UrlEncode Method, that how I understand your question makes more sense it the context. This is the documentation for the method: https://learn.microsoft.com/de-de/dotnet/api/system.net.webutility.urlencode
The Url you are generating is invalid. You need to use Uri.EscapeDataString to convert the url param into a string that can be appended to a url.
// For this example we check if a well formed absolute Uri was provided
// and load that Url, all others will be loaded using the search engine
// e.g. https://github.com will load directly, attempting to load
// github.com will load the search engine with github.com as the query.
//
if (Uri.IsWellFormedUriString(url, UriKind.Absolute))
{
chromiumWebBrowser.LoadUrl(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + Uri.EscapeDataString(url);
chromiumWebBrowser.LoadUrl(searchUrl);
}
nothing happens and it dosent load the search engine
You need to subscribe to the LoadError event to get actual error messages. It's up to you to display errors to the user. The following is a basic example:
chromiumWebBrowser.LoadError += OnChromiumWebBrowserLoadError;
private void OnChromiumWebBrowserLoadError(object sender, LoadErrorEventArgs e)
{
//Actions that trigger a download will raise an aborted error.
//Aborted is generally safe to ignore
if (e.ErrorCode == CefErrorCode.Aborted)
{
return;
}
var errorHtml = string.Format("<html><body><h2>Failed to load URL {0} with error {1} ({2}).</h2></body></html>",
e.FailedUrl, e.ErrorText, e.ErrorCode);
_ = e.Browser.SetMainFrameDocumentContentAsync(errorHtml);
}
For testing purposes you can also copy and paste the searchUrl string you've generated and try loading it in Chrome to see what happens, you should also get an error.
Is there any way in ASP.net C# to treat sub-domain as query string?
I mean if the user typed london.example.com then I can read that he is after london data and run a query based on that. example.com does not currently have any sub-domains.
This is a DNS problem more than an C#/ASP.Net/IIS problem. In theory, you could use a wildcard DNS record. In practice, you run into this problem from the link:
The exact rules for when a wild card will match are specified in RFC 1034, but the rules are neither intuitive nor clearly specified. This has resulted in incompatible implementations and unexpected results when they are used.
So you can try it, but it's not likely to end well. Moreover, you can fiddle with things until it works in your testing environment, but that won't be able to guarantee things go well for the general public. You'll likely do much better choosing a good DNS provider with an API, and writing code to use the API to keep individual DNS entries in sync. You can also set up your own public DNS server, though I strongly recommend using a well-known and reputable commercial DNS host.
An additional problem you can run into is the TLS/SSL certificate (because of course you're gonna use HTTPS. Right? RIGHT!?) You can try a wild card certificate and probably be okay, but depending on what else you do you may find it's not adequate; suddenly you're needing to provision a separate SSL certificate for every city entry in your database, and that can be a real pain, even via the Let's Encrypt service.
If you do try it, IIS is easily capable of mapping the requests to your ASP.Net app based on a wildcard host name, and ASP.Net itself is easily capable of reading and parsing the host name out of the request and returning different results based on that. IIS URL re-writing should be able to help with this, though I'm not sure whether you can do stock MVC routing in C#/ASP.Net based on this attribute.
I have to add to the previous answers, that after you fix the dns, and translate the subdomain to some parameters you can use the RewritePath to move that parameters to your pages.
For example let say that a function PathTranslate(), translate the london.example.com to example.com/default.aspx?Town=1
Then you use the RewritePath to keep the sub-domain and at the same time send your parameters to your page.
string sThePathToReWrite = PathTranslate();
if (sThePathToReWrite != null){
HttpContext.Current.RewritePath(sThePathToReWrite, false);
}
string PathTranslate()
{
string sCurrentPath = HttpContext.Current.Request.Path;
string sCurrentHost = HttpContext.Current.Request.Url.Host;
//... lot of code ...
return strTranslatedUrl
}
A low tech solution can be like this: (reference: https://www.pavey.me/2016/03/aspnet-c-extracting-parts-of-url.html)
public static List<string> SubDomains(this HttpRequest Request)
{
// variables
string[] requestArray = Request.Host().Split(".".ToCharArray());
var subDomains = new List<string>();
// make sure this is not an ip address
if (Request.IsIPAddress())
{
return subDomains;
}
// make sure we have all the parts necessary
if (requestArray == null)
{
return subDomains;
}
// last part is the tld (e.g. .com)
// second to last part is the domain (e.g. mydomain)
// the remaining parts are the sub-domain(s)
if (requestArray.Length > 2)
{
for (int i = 0; i <= requestArray.Length - 3; i++)
{
subDomains.Add(requestArray[i]);
}
}
// return
return subDomains;
}
// e.g. www
public static string SubDomain(this HttpRequest Request)
{
if (Request.SubDomains().Count > 0)
{
// handle cases where multiple sub-domains (e.g. dev.www)
return Request.SubDomains().Last();
}
else
{
// handle cases where no sub-domains
return string.Empty;
}
}
// e.g. azurewebsites.net
public static string Domain(this HttpRequest Request)
{
// variables
string[] requestArray = Request.Host().Split(".".ToCharArray());
// make sure this is not an ip address
if (Request.IsIPAddress())
{
return string.Empty;
}
// special case for localhost
if (Request.IsLocalHost())
{
return Request.Host().ToLower();
}
// make sure we have all the parts necessary
if (requestArray == null)
{
return string.Empty;
}
// make sure we have all the parts necessary
if (requestArray.Length > 1)
{
return $"{requestArray[requestArray.Length - 2]}.{requestArray[requestArray.Length - 1]}";
}
// return empty string
return string.Empty;
}
Following question is similar to yours:
Using the subdomain as a parameter
I have to replace string in comment with link to overlap. There's code in PHP:
$comment = str_replace('[%account]','account',$comment);
And I need to to the same thing in C#, eventually in HTML, becouse is ASP.NET MVC app. I know there's a method called Replace(string OldValue, string NewValue), but I believe it is only for string type, not for links. Or Am I wrong? Any ideas?
I trie to do it with class property like this:
public string AccountLink { get { return "account"; } }
and then:
parcel.Comment = parcelStatus.Comment.Replace("[%account]", parcel.AccountLink)
But I don't know how to connect the word "account" with that link from PHP code above.
I realize there are a ton of articles and resources out there on this subject, but all seem to only show how to move a querystring like category=shoes around the url to a differently place, like this products/{category}
Well i have the following querystring: profile.aspx?q=98c2b15f-90c3-4a7f-a33f-0e34b106877e
I was trying to implement a RoutHandler to query the DB to find the users name and create a url like mydomain.com/usersname
This is what i tried (everything is hard coded right now till i get it working):
void Application_Start(object sender, EventArgs e)
{
RegisterRoute(System.Web.Routing.RouteTable.Routes);
}
void RegisterRoute(System.Web.Routing.RouteCollection routes)
{
routes.Add("Profiles", new System.Web.Routing.Route("profile/{profile}", new RouteHandler()));
}
And this is the handler class:
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
string username = requestContext.RouteData.Values["profile"] as string;
HttpContext.Current.Items["q"] = "98c2b15f-90c3-4a7f-a33f-0e34b106877e";
return BuildManager.CreateInstanceFromVirtualPath("~/pub/profile.aspx", typeof(Page)) as Page;
}
Profile.aspx actually looks for the "q" querystring. And with the above setup, it does not find it.
What am i doing wrong? How do i route or rewrite the url so that it is pretty + keep it so the page can find the querystrings it needs?
Any help would be great. Thanks in advance.
First thing - If you are using .net framework 4 you dont need to create any handler, you can directly use MapPageRoute method to a route.
Answer to your question-
use can use foreach loop like below in handler rather than looking for "profile" specifically.
foreach (var urlParm in requestContext.RouteData.Values)
requestContext.HttpContext.Items[urlParm.Key] = urlParm.Value;
return BuildManager.CreateInstanceFromVirtualPath(VirtualPath, typeof(Page)) as IHttpHandler
and in your routed page you should check for
string userName = this.Context.Items["profile"].ToString(); // "userName" and is set as route parameters in Global.asax
You set VirtualPath in RouteHandler constructor
RouteHandler(string virPath)
{
this.VirtualPath = virPath;
}
see these links for more information-
http://www.codeproject.com/Articles/77199/URL-Routing-with-ASP-NET-4-0
http://msdn.microsoft.com/en-us/library/ie/cc668201.aspx
I'm currently going through the ASP.NET MVC NerdDinner tutorial and am having a problem with a particular helper method related to user authorization. The idea is that only users who "own" a particular dinner should be able to edit or delete it (based on the Dinner object's HostedBy property).
I have the following method in my Dinner object:
public partial class Dinner {
public bool IsHostedBy(string userName) {
return HostedBy.Equals(userName, StringComparison.InvariantCultureIgnoreCase);
}
// other stuff removed for brevity
}
and in my View I'm trying to show/hide links based on whether the logged in user is the dinner's host:
<% if (Model.IsHostedBy(Context.User.Identity.Name)) { %>
<%= Html.ActionLink("Edit Dinner", "Edit", new { id = Model.DinnerID })%>
|
<%= Html.ActionLink("Delete Dinner", "Delete", new { id = Model.DinnerID })%>
<% } %>
The problem is that IsHostedBy() never returns true. I've written User.Identity.Name and Dinner.HostedBy to the screen to verify they're the same, but the method still returns false. I'm uncertain how to track down the problem.
I'm new to both C# and ASP.NET MVC, so it's very likely I'm missing something easy. Any help is appreciated and I'd be happy to post more information if it's needed.
While I'm at it I may as well write the Answer.
Check for errent spaces in the two strings.
I'm guessing that HostedBy and userName aren't actually the same string!
Some debugging ideas:
1st) Try forcing it to always return true:
public bool IsHostedBy(string userName) {
return true;
}
If this lets you return true back into the view, at least you can know that the code you're writing in the IsHostedBy method is being executed.
2nd) Add a console-out to see for yourself if the two strings are indeed equal:
public bool IsHostedBy(string userName) {
Console.WriteLine("userName: {0} / HostedBy: {1}", userName, HostedBy);
return true;
}
This will help you inspect the values of these items. Or you could just set a breakpoint at the return statement and see what they are as well.