Currently I am using Amazon Cloudfront to service static objects on my ASP.Net MVC3 C# site. So all static resources have http://cdn.domainname.com/ appended before the resource.
At the same time I am using combres and combred mvc to compress and combine my CSS and Javascript.
The tag to output the minimized combined files are as follows.
#Html.Raw(WebExtensions.CombresLink("siteCss"))
#Html.Raw(WebExtensions.CombresLink("siteJs"))
This produces links on my site to
<link rel="stylesheet" type="text/css" href="/combres.axd/siteCss/-63135510/"/>
<script type="text/javascript" src="/combres.axd/siteJs/-561397631/"></script>
As you can see my cloudfront cdn isn't in front of it so I am not getting the benefits of cloudfront with these to files.
Is there anyone out there who knows how to insert my cdn without changing the source code of the actuall combress dll file?
I'm not familiar with Cloudfront, but with Combres (latest release) you can change the host name (which gets appended as prefix before the /combres.axd... by setting the host attribute in . For example:
<resourceSets url="~/combres.axd"
host="static.mysite.com"
defaultDuration="365"
defaultVersion="auto"
defaultDebugEnabled="false"
defaultIgnorePipelineWhenDebug="true"
localChangeMonitorInterval="30"
remoteChangeMonitorInterval="60"
>
Please let me know if this approach works with CloudFront?
I ran in the same issue a few months ago and just ran across this post. I was able to get around it by making my own Combres filter (FixUrlsInCSSFilter) that will read a "Base Url" value from the web.config or a database setting and apply it to all combres image urls.
Hope it helps someone out there...
combres.xml:
<combres xmlns='urn:combres'>
<filters>
<filter type="MySite.Filters.FixUrlsInCssFilter, MySite" />
</filters>
FixUrlsInCssFilter - most of this was copied from the original reflected file
public sealed class FixUrlsInCssFilter : ISingleContentFilter
{
/// <inheritdoc cref="IContentFilter.CanApplyTo" />
public bool CanApplyTo(ResourceType resourceType)
{
return resourceType == ResourceType.CSS;
}
/// <inheritdoc cref="ISingleContentFilter.TransformContent" />
public string TransformContent(ResourceSet resourceSet, Resource resource, string content)
{
string baseUrl = AppSettings.GetImageBaseUrl();
return Regex.Replace(content, #"url\((?<url>.*?)\)", match => FixUrl(resource, match, baseUrl),
RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.ExplicitCapture);
}
private static string FixUrl(Resource resource, Match match, string baseUrl)
{
try
{
const string template = "url(\"{0}\")";
var url = match.Groups["url"].Value.Trim('\"', '\'');
while (url.StartsWith("../", StringComparison.Ordinal))
{
url = url.Substring(3); // skip one '../'
}
if (!baseUrl.EndsWith("/"))
baseUrl += "/";
if (baseUrl.StartsWith("http"))
{
return string.Format(CultureInfo.InvariantCulture, template, baseUrl + url);
}
else
return string.Format(CultureInfo.InvariantCulture, template, (baseUrl + url).ResolveUrl());
}
catch (Exception ex)
{
// Be lenient here, only log. After all, this is just an image in the CSS file
// and it should't be the reason to stop loading that CSS file.
EventManager.RaiseExceptionEvent("Cannot fix url " + match.Value, ex);
return match.Value;
}
}
}
#region Required to override FixUrlsInCssFilter for Combres
public static class CombresExtensionMethods
{
/// <summary>
/// Returns the relative HTTP path from a partial path starting out with a ~ character or the original URL if it's an absolute or relative URL that doesn't start with ~.
/// </summary>
public static string ResolveUrl(this string originalUrl)
{
if (string.IsNullOrEmpty(originalUrl) || IsAbsoluteUrl(originalUrl) || !originalUrl.StartsWith("~", StringComparison.Ordinal))
return originalUrl;
/*
* Fix up path for ~ root app dir directory
* VirtualPathUtility blows up if there is a
* query string, so we have to account for this.
*/
var queryStringStartIndex = originalUrl.IndexOf('?');
string result;
if (queryStringStartIndex != -1)
{
var baseUrl = originalUrl.Substring(0, queryStringStartIndex);
var queryString = originalUrl.Substring(queryStringStartIndex);
result = string.Concat(VirtualPathUtility.ToAbsolute(baseUrl), queryString);
}
else
{
result = VirtualPathUtility.ToAbsolute(originalUrl);
}
return result.StartsWith("/", StringComparison.Ordinal) ? result : "/" + result;
}
private static bool IsAbsoluteUrl(string url)
{
int indexOfSlashes = url.IndexOf("://", StringComparison.Ordinal);
int indexOfQuestionMarks = url.IndexOf("?", StringComparison.Ordinal);
/*
* This has :// but still NOT an absolute path:
* ~/path/to/page.aspx?returnurl=http://www.my.page
*/
return indexOfSlashes > -1 && (indexOfQuestionMarks < 0 || indexOfQuestionMarks > indexOfSlashes);
}
}
#endregion
AppSettings class - to retrieve the value from the web.config. I also use this to build the path for images not handled by combres...
public class AppSettings
{
/// <summary>
/// Retrieves the value for "ImageBaseUrl" if the key exists
/// </summary>
/// <returns></returns>
public static string GetImageBaseUrl()
{
string baseUrl = "";
if (ConfigurationManager.AppSettings["ImageBaseUrl"] != null)
baseUrl = ConfigurationManager.AppSettings["ImageBaseUrl"];
return baseUrl;
}
}
web.config values
<appSettings>
<add key="ImageBaseUrl" value="~/Content/Images/" /> <!--For Development-->
<add key="ImageBaseUrl" value="https://d209523005EXAMPLE.cloudfront.net/Content/Images/" /> <!--For Production-->
</appSettings>
Related
I have global and local embedded resources in my project as shown in the image.
Resources files in my project with build action as embedded resources
I have a function ResourceText as below
public static string GLOBAL_RESOURCES = "SampleClient.App_GlobalResources.Global.resources";
/// <summary>
/// Used in JavaScript/front code to return resource translations for current page or global resource file
/// </summary>
/// <param name="pResourceKey"></param>
/// <returns></returns>
/// <remarks></remarks>
public string ResourceText(string pResourceKey, bool pGlobalResource = false)
{
if (string.IsNullOrEmpty(pResourceKey)) throw new ArgumentNullException("ResourceKey cannot be empty");
if (pGlobalResource)
{
// Find the value from the global resource
ResourceManager tResourceManager = new System.Resources.ResourceManager(GLOBAL_RESOURCES.Replace(".resources", ""), this.GetType().BaseType.Assembly);
tResourceManager.IgnoreCase = true;
string tTranlsation = tResourceManager.GetString(pResourceKey);
return string.IsNullOrEmpty(tTranlsation) ? pResourceKey : tTranlsation;
}
else
{
string[] tAssemblyNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
try
{
if (tAssemblyNames.Length >= 1) // There is a local file associated
{
// Get value from the local resource
string tAssemblyName = this.Page.GetType().BaseType.FullName.Insert(this.Page.GetType().BaseType.FullName.LastIndexOf(".") + 1, "App_LocalResources.");
string tResName = (from n in tAssemblyNames where n.Contains(tAssemblyName + ".aspx") select n).First().Replace(".resources", "");
ResourceManager tResourceManager = new System.Resources.ResourceManager(tResName, this.GetType().BaseType.Assembly);
tResourceManager.IgnoreCase = true;
string tTranlsation = tResourceManager.GetString(pResourceKey);
return string.IsNullOrEmpty(tTranlsation) ? pResourceKey : tTranlsation;
}
}
catch (Exception ex)
{
throw (ex);
// Check the local resources
}
}
// Fall back
return pResourceKey;
}
Which is called in my aspx page as
<input type="search" id="inputCustomerGroupGridSearch" placeholder="<%= ResourceText("PlaceholderSearch")%>" />
<button type="button" id="buttonNewCustomerGroup" style="float: right" class="PrimaryButton"><%=ResourceText("ButtonNew")%></button>
When I debugged the function ResourceText, the line of code
string[] tAssemblyNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
returns only "SampleClient.App_GlobalResources.Global.resources" not "SampleClient.Modules.Customers.App_LocalResources.Customers.resouces". Why is the resources in App_LocalResources not returned by Assembly.GetExecutingAssembly().GetManifestResourceNames()?
Resolved: I added strong typed assembly App_LocalResources.resources.dll in my bin folder. Then it was listed in resources names when executing Assembly.GetExecutingAssembly().GetManifestResourceNames();
So, I could call my ResourceText function for both global and local resources.
I am building a set of tests for an automation framework, but am running into an issue navigating to a local HTML page I have created.
Here is where I'm creating the ChromeDriver instance.
if (AllowFileAccessAcrossFiles)
{
ChromeOptions options = new ChromeOptions();
// Have tried, none, individually, as well as both.
options.AddArgument("--allow-file-access-from-files");
options.AddArgument("--enable-local-file-accesses ");
driver = new ChromeDriver(options);
}
This ChromeDriver instance is later passed into the NgWebDriver class so that I am able to use Protractor-net in my tests as well as abstract the test tools.
internal TestWebDriver(RemoteWebDriver driver, TestConfiguration configuration)
{
// ...
_driver = new NgWebDriver(driver);
// ...
}
When the framework calls into the driver to navigate to the page it passes the correct file path ("file:/// ..."), but it never makes it into the browser URL and is not navigated to. (i.e. the URL says data;)
How do I navigate to a local HTML page with a file path with ChromeDriver?
It turns out that this resolution to this issue is rooted in NgWebDriver. NgWebDriver defers to the drivers for IE, Edge, PhantomJS, Firefox, and Safari to navigate to the URL, but if it is anything else then it just runs this: this.ExecuteScript("window.name += '" + AngularDeferBootstrap + "'; window.location.href = '" + value + "';");
The JavaScript method that is being called doesn't handle just passing in a local path, it needs an http(s) string to navigate. So whether or not we can pass in a local path is up to the specific driver's implementation of the set method for the Url property.
Below is the relevant Protractor-net property.
public class NgWebDriver : IWebDriver, IWrapsDriver, IJavaScriptExecutor
{
private const string AngularDeferBootstrap = "NG_DEFER_BOOTSTRAP!";
private IWebDriver driver;
private IJavaScriptExecutor jsExecutor;
private string rootElement;
private IList<NgModule> mockModules;
// constructors and stuff
/// <summary>
/// Gets or sets the URL the browser is currently displaying.
/// </summary>
public string Url
{
get
{
this.WaitForAngular();
return this.driver.Url;
}
set
{
// Reset URL
this.driver.Url = "about:blank";
// TODO: test Android
IHasCapabilities hcDriver = this.driver as IHasCapabilities;
if (hcDriver != null &&
(hcDriver.Capabilities.BrowserName == "internet explorer" ||
hcDriver.Capabilities.BrowserName == "MicrosoftEdge" ||
hcDriver.Capabilities.BrowserName == "phantomjs" ||
hcDriver.Capabilities.BrowserName == "firefox" ||
hcDriver.Capabilities.BrowserName.ToLower() == "safari"))
{
this.ExecuteScript("window.name += '" + AngularDeferBootstrap + "';");
this.driver.Url = value;
}
else
{
this.ExecuteScript("window.name += '" + AngularDeferBootstrap + "'; window.location.href = '" + value + "';");
}
if (!this.IgnoreSynchronization)
{
try
{
// Make sure the page is an Angular page.
long? angularVersion = this.ExecuteAsyncScript(ClientSideScripts.TestForAngular) as long?;
if (angularVersion.HasValue)
{
if (angularVersion.Value == 1)
{
// At this point, Angular will pause for us, until angular.resumeBootstrap is called.
// Add default module for Angular v1
this.mockModules.Add(new Ng1BaseModule());
// Register extra modules
foreach (NgModule ngModule in this.mockModules)
{
this.ExecuteScript(ngModule.Script);
}
// Resume Angular bootstrap
this.ExecuteScript(ClientSideScripts.ResumeAngularBootstrap,
String.Join(",", this.mockModules.Select(m => m.Name).ToArray()));
}
else if (angularVersion.Value == 2)
{
if (this.mockModules.Count > 0)
{
throw new NotSupportedException("Mock modules are not supported in Angular 2");
}
}
}
}
catch (WebDriverTimeoutException wdte)
{
throw new InvalidOperationException(
String.Format("Angular could not be found on the page '{0}'", value), wdte);
}
}
}
}
Since this property assumes that an application is using Angular, when navigating with Navigate().GoToUrl() you must include, again, whether the application is using Angular via a bool.
In our case, we were not using Angular and passing that into the GoToUrl() method calls directly into the wrapped IWebDriver via INavigation. This wrapped driver handles local files correctly.
Below is the navigation class in Protractor-net:
public class NgNavigation : INavigation
{
private NgWebDriver ngDriver;
private INavigation navigation;
// irrelevant constructors and such
/// <summary>
/// Load a new web page in the current browser window.
/// </summary>
/// <param name="url">The URL to load. It is best to use a fully qualified URL</param>
/// <param name="ensureAngularApp">Ensure the page is an Angular page by throwing an exception.</param>
public void GoToUrl(string url, bool ensureAngularApp)
{
if (ensureAngularApp)
{
this.ngDriver.Url = url;
}
else
{
this.navigation.GoToUrl(url);
}
}
I have a URL and from which i need to get names after "bussiness" and Before the Page Name i.e. "paradise-villas-little.aspx" from below URL.
http://test.com/anc/bussiness/accommo/resort/paradise-villas-little.aspx
I am not getting how can i get this. i have tried the RawUrl, but it fetched the full. Please help me how can i do this.
UPDATE: This is a type of URL, i need to check it for dynamically.
You can create a little helper, and parse the URL from it's Uri Segments :
public static class Helper
{
public static IEnumerable<String> ExtractSegments(this Uri uri, String exclusiveStart)
{
bool startFound = false;
foreach (var seg in uri.Segments.Select(i => i.Replace(#"/","")))
{
if (startFound == false)
{
if (seg == exclusiveStart)
startFound = true;
}
else
{
if (!seg.Contains("."))
yield return seg;
}
}
}
}
And call it like this :
Uri uri = new Uri(#"http://test.com/anc/bussiness/accommo/resort/paradise-villas-little.aspx");
var found = uri.ExtractSegments("bussiness").ToList();
Then found contains "accommo" and "resort", and this method is extensible to any URL length, with or without file name at the end.
Nothing sophisticated in this implementation, just regular string operations:
string url = "http://test.com/anc/bussiness/accommo/resort/paradise-villas-little.aspx";
string startAfter = "business";
string pageName = "paradise-villas-little.aspx";
char delimiter = '/'; //not platform specific
var from = url.IndexOf(startAfter) + startAfter.Length + 1;
var to = url.Length - from - pageName.Length - 1;
var strings = url.Substring(from, to).Split(delimiter);
You may want to add validations though.
You have to use built-in string methods. The best is to use String Split.
String url = "http://test.com/anc/bussiness/accommo/resort/paradise-villas-little.aspx";
String[] url_parts = url.Split('/'); //Now you have all the parts of the URL all folders and page. Access the folder names from string array.
Hope this helps
Summary
I have an ASP.NET 3.5 website and a mobile detection method inside a C# class file inside my app_code folder. I want to call this method which sets a cookie, then switch my master page file if it's a mobile device.
I'm using a method i got from the comment section down in this article: http://www.codeproject.com/Articles/34422/Detecting-a-mobile-browser-in-ASP-NET
This just seemed simpler than using the 51degrees method of detection since i didn't really need a high level of detection, and i didn't want to send them to a different URL, but rather just flip to a different masterpage, and the NuGet package which makes a nice easy install doesn't work for ASP.NET 3.5.
The problem i'm at currently is with calling the method.
Here's the Code
External app_code class
public static class fooBar // test method
{
public static bool ean()
{
return true;
}
}
public static class HttpRequestExt
{
#region Private Fields
// These regular expressions retrieved from http://detectmobilebrowser.com/ "Open source mobile phone detection".
private static Regex MobileBrowsers = new Regex(#"android|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino", RegexOptions.IgnoreCase | RegexOptions.Multiline);
private static Regex MobileApps = new Regex(#"1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|e\\-|e\\/|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\\-|2|g)|yas\\-|your|zeto|zte\\-", RegexOptions.IgnoreCase | RegexOptions.Multiline);
#endregion
public const string ViewMobileSiteCookieName = "ViewMobile";
/// <summary>
/// Determines if the request emanated from a mobile-device client;
/// and stores the result in a cookie on the response.
/// </summary>
/// <param name="request"></param>
/// <param name="Response"></param>
/// <returns></returns>
///
public static bool IsMobileClient(this System.Web.HttpRequest request, System.Web.HttpRequest Response)
{
bool isMobile = false;
bool isCookieSet = false;
var viewMobileCookie = request.Cookies[ViewMobileSiteCookieName];
if (viewMobileCookie != null && bool.TryParse(viewMobileCookie.Value, out isMobile))
{
isCookieSet = true;
}
else if (request.Browser.IsMobileDevice)
{
isMobile = true;
}
else if (request.ServerVariables["HTTP_X_WAP_PROFILE"].IsNotEmpty())
{
isMobile = true;
}
else if
(
request.ServerVariables["HTTP_ACCEPT"].IsNotEmpty()
&&
(
request.ServerVariables["HTTP_ACCEPT"].ToLower().Contains("wap")
|| request.ServerVariables["HTTP_ACCEPT"].ToLower().Contains("wml+xml")
)
)
{
isMobile = true;
}
else if (request.ServerVariables["HTTP_USER_AGENT"].IsNotEmpty())
{
string userAgent = request.ServerVariables["HTTP_USER_AGENT"];
isMobile = ((MobileBrowsers.IsMatch(userAgent) || MobileApps.IsMatch(userAgent.Substring(0, 4))));
}
// Store the result as a cookie.
if (!isCookieSet)
Response.Cookies.Add(new HttpCookie(ViewMobileSiteCookieName, isMobile.ToString()));
return isMobile;
}
public static bool IsNotEmpty(this string instance)
{
return instance != null && instance.Length > 0;
}
}
My call to it)
Right now im doing it on the page, but i figure i'll do this in global.asax on session start?
sectionTitle.InnerHtml = fooBar.ean().ToString(); // test works
sectionTitle.InnerHtml = HttpRequestExt.IsMobileClient.ToString(); // compile error
Compile Error:
CS0119: 'SWIC.HttpRequestExt.IsMobileClient(System.Web.HttpRequest, System.Web.HttpRequest)' is a 'method', which is not valid in the given context
Do i have to somehow cast this to the current instance? Should i just be doing this differently all together?
You're trying to call a method like a property. Methods need parentheses:
HttpRequestExt.IsMobileClient().ToString()
^^
You'll also have to call it on the current request, not just statically, as it is an extension method (which takes a parameter). E.g.:
sectionTitle.InnerHtml = Page.Request.IsMobileClient(Page.Response).ToString();
In my IHttpHandler class (for an .ashx page), I want to search a directory for certain files, and return relative urls. I can get the files, no problem:
string dirPath = context.Server.MapPath("~/mydirectory");
string[] files = Directory.GetFiles(dirPath, "*foo*.txt");
IEnumerable<string> relativeUrls = files.Select(f => WHAT GOES HERE? );
What is the easiest way to convert file paths to relative urls? If I were in an aspx page, I could say this.ResolveUrl(). I know I could do some string parsing and string replacement to get the relative url, but is there some built-in method that will take care of all of that for me?
Edit: To clarify, without doing my own string parsing, how do I go from this:
"E:\Webs\WebApp1\WebRoot\mydirectory\foo.txt"
to this:
"/mydirectory/foo.txt"
I'm looking for an existing method like:
public string GetRelativeUrl(string filePath) { }
I can imagine a lot of people having this question... My solution is:
public static string ResolveRelative(string url)
{
var requestUrl = context.Request.Url;
string baseUrl = string.Format("{0}://{1}{2}{3}",
requestUrl.Scheme, requestUrl.Host,
(requestUrl.IsDefaultPort ? "" : ":" + requestUrl.Port),
context.Request.ApplicationPath);
if (toresolve.StartsWith("~"))
{
return baseUrl + toresolve.Substring(1);
}
else
{
return new Uri(new Uri(baseUrl), toresolve).ToString();
}
}
update
Or from filename to virtual path (haven't tested it; you might need some code similar to ResoveRelative above as well... let me know if it works):
public static string GetUrl(string filename)
{
if (filename.StartsWith(context.Request.PhysicalApplicationPath))
{
return context.Request.ApplicationPath +
filename.Substring(context.Request.PhysicalApplicationPath.Length);
}
else
{
throw new ArgumentException("Incorrect physical path");
}
}
try System.Web.Hosting.HostingEnvironment.MapPath method, its static and can be accessed everywhere in web application.