I have localized MVC according to Nadeem Afana's blog and using a script translator similar to Mads Kristensen's blog. The problem is that bundles are registered in Application_Start method. This causes the scripts are translated in one - default - language and stored in the browser/server cache. Changing the language/culture will not generate their linguistic equivalent. Is it possible to implement a cache profile VaryByCustom = "culture" similarly to Views? Is there any better practice/solution? Is it possible to use HTML5 Application Cache with translated scripts?
Script translator class:
public class ScriptTranslator : IBundleTransform {
public ScriptTranslator(ResourceManager manager) {
RM = manager;
}
public void Process(BundleContext context, BundleResponse response) {
response.Content = TranslateScript(response.Content);
}
private static ResourceManager RM;
private static Regex REGEXP = new Regex( #"translate\(""([^\))]*)""\)", RegexOptions.Singleline | RegexOptions.Compiled);
private string TranslateScript(string text) {
MatchCollection matches = REGEXP.Matches(text);
foreach (Match key in matches) {
object obj = RM.GetObject(kay.Groups[1].Value);
if (obj != null) {
text = text.Replace(kay.Value, CleanText(obj.ToString()));
}
}
return text;
}
private static string CleanText(string text) {
return string.Format("\"{0}\"", text.Replace("\\", "\\\\"));
}
}
Resource files using Custom tool namespace Resources.Javascript; My bundle config is:
public class BundleConfig {
public static void RegisterBundles(BundleCollection bundles) {
var DEFAULT_SCRIPT_PATH = "~/Scripts/Modules/";
var DEFAULT_SCRIPT_BOUNDLE_PATH = "~/ScriptBundles/";
var mainBoundle = new ScriptBundle(DEFAULT_SCRIPT_BOUNDLE_PATH + "main")
.Include(DEFAULT_SCRIPT_PATH + "test.js");
mainBoundle.Transforms.Clear();
mainBoundle.Transforms.Add(new ScriptTranslator(Resources.JavaScript.test.ResourceManager));
mainBoundle.Transforms.Add(new JsMinify());
bundles.Add(mainBoundle);
}
}
Our solution for this problem was not only to store different bundles by controller/action combination but also by CurrentUICulture.
string.Format("scriptsDependency{0}{1}_{2}", controler, action, Thread.CurrentThread.CurrentUICulture.Name);
I also recommend to store static libraries like JQuery or Bootstrap. But for dynamic content i would recommend NoCache policy.
public class NonCacheableTransformer : IBundleTransform
{
public void Process(BundleContext context, BundleResponse response)
{
context.UseServerCache = false;
response.Cacheability = HttpCacheability.NoCache;
}
}
Related
How can I take screenshots for different steps performing in execution of an automated test for android/iOS mobile in C# language?
There appear to be numerous suggestions on how to do this.
This is one places code in OnCreateView():
public static Android.Content.Context Context { get; private set; }
public override View OnCreateView(View parent, string name, Context context, IAttributeSet attrs)
{
MainActivityContext = context;
return base.OnCreateView(parent, name, context, attrs);
}`
Then, I wrote a service implemenatation in which I take a screen capture, by using the static Context of the MainActivity, like this :
`public class SnapshotService : ISnapshotService
{
public void Capture()
{
var screenshotPath =
Android.OS.Environment.GetExternalStoragePublicDirectory("Pictures").AbsolutePath +
Java.IO.File.Separator +
"screenshot.png";
var rootView = ((Android.App.Activity)MainActivity.Context).Window.DecorView.RootView;
using (var screenshot = Android.Graphics.Bitmap.CreateBitmap(
rootView.Width,
rootView.Height,
Android.Graphics.Bitmap.Config.Argb8888))
{
var canvas = new Android.Graphics.Canvas(screenshot);
rootView.Draw(canvas);
using (var screenshotOutputStream = new System.IO.FileStream(
screenshotPath,
System.IO.FileMode.Create))
{
screenshot.Compress(Android.Graphics.Bitmap.CompressFormat.Png, 90, screenshotOutputStream);
screenshotOutputStream.Flush();
screenshotOutputStream.Close();
}
}
}
}`
C#
You can use this piece of code:
ScenarioContext.Current.Get<IApp>("Application").Screenshot(ScenarioStepContext.Current.StepInfo.Text);
I want to access my create.sql file in the main folder of my server. It contains queries to set up my database. I have a problem to access this file at all.
1) I cannot really get there through Configuration. I can only use AddJsonFile, AddXmlFile, and AddIniFile. And I guess this is not the best idea to put a big sql file into any of those.
2) Mvc source on github seems to be missing MapPath. So no possibility of using Server.MapPath("~/create.sql").
How to achieve this then?
As already noticed and mentioned in the comments it seems that there is no MapPath in ASP.NET VNext (MVC 6). I found the workaround here:
http://forums.asp.net/t/2005166.aspx?HostingEnvironment+Equivalent+For+MapPath
Basically you need to get the ApplicationBasePath from IApplicationEnvironment interface, which currently is implemented as a service, following below the solution:
private readonly IApplicationEnvironment _appEnvironment;
public HomeController(IApplicationEnvironment appEnvironment)
{
_appEnvironment = appEnvironment;
}
public IActionResult Index()
{
var rootPath = _appEnvironment.ApplicationBasePath;
return View();
}
And also, instead of injecting IApplicationEnvironment you may use PlatformServices.Default.Application.ApplicationBasePath.
EDIT: Here's a possible implementation of MapPath/UnmapPath as extensions to PlatformServices:
removed (see EDIT2)
EDIT2: Slightly modified, IsPathMapped() added as well as some checks to see if path mapping/unmapping is really needed.
public static class PlatformServicesExtensions
{
public static string MapPath(this PlatformServices services, string path)
{
var result = path ?? string.Empty;
if (services.IsPathMapped(path) == false)
{
var wwwroot = services.WwwRoot();
if (result.StartsWith("~", StringComparison.Ordinal))
{
result = result.Substring(1);
}
if (result.StartsWith("/", StringComparison.Ordinal))
{
result = result.Substring(1);
}
result = Path.Combine(wwwroot, result.Replace('/', '\\'));
}
return result;
}
public static string UnmapPath(this PlatformServices services, string path)
{
var result = path ?? string.Empty;
if (services.IsPathMapped(path))
{
var wwwroot = services.WwwRoot();
result = result.Remove(0, wwwroot.Length);
result = result.Replace('\\', '/');
var prefix = (result.StartsWith("/", StringComparison.Ordinal) ? "~" : "~/");
result = prefix + result;
}
return result;
}
public static bool IsPathMapped(this PlatformServices services, string path)
{
var result = path ?? string.Empty;
return result.StartsWith(services.Application.ApplicationBasePath,
StringComparison.Ordinal);
}
public static string WwwRoot(this PlatformServices services)
{
// todo: take it from project.json!!!
var result = Path.Combine(services.Application.ApplicationBasePath, "wwwroot");
return result;
}
}
EDIT3: PlatformServices.WwwRoot() return the actual execution path and in .net core 2.0, DEBUG mode it is xxx\bin\Debug\netcoreapp2.0, which, obviously is not what is required. Instead, replace PlatformServices with IHostingEnvironment and use environment.WebRootPath.
How can I iterate through file names in the 'Default Document' IIS feature for an application in C#?
I am using Microsoft.Web.Administration.ServerManager.
Thanks
You can do it using its "loosely" typed model, basically for reading it for Default Web Site would look like:
using (ServerManager serverManager = new ServerManager())
{
Configuration webConfig = serverManager.GetWebConfiguration("Default Web Site");
ConfigurationSection section = webConfig.GetSection("system.webServer/defaultDocument");
foreach (ConfigurationElement item in section.GetCollection("files"))
{
Console.WriteLine(item["value"]);
}
}
You can also generate strongly-typed wrappers for collections and entries you want to use frequently which makes it a lot cleaner and prevents mistakes, that would make it look like:
using (ServerManager serverManager = new ServerManager())
{
Configuration webConfig = serverManager.GetWebConfiguration("Default Web Site");
DefaultDocumentSection section = (DefaultDocumentSection)webConfig.GetSection("system.webServer/defaultDocument", typeof(DefaultDocumentSection));
foreach (FileElement item in section.Files)
{
Console.WriteLine(item.Value);
}
}
And for that to work you need the following "strongly-typed-wrappers":
public class DefaultDocumentSection : ConfigurationSection
{
private FilesCollection _files;
public FilesCollection Files
{
get
{
if (_files == null)
{
_files = (FilesCollection)base.GetCollection("files", typeof(FilesCollection));
}
return _files;
}
}
}
public class FilesCollection : ConfigurationElementCollectionBase<FileElement>
{
protected override FileElement CreateNewElement(string elementTagName)
{
return new FileElement();
}
}
public class FileElement : ConfigurationElement
{
public string Value { get { return (string)base["value"]; } }
}
I have a code in VB6. Can anyone tell me how to write it in C#. This code is below:
Set Amibroker = CreateObject("Broker.Application")
Set STOCK = Amibroker.Stocks.Add(ticker)
Set quote = STOCK.Quotations.Add(stInDate)
quote.Open = stInOpen
quote.High = stInHigh
quote.Low = stInlow
quote.Close = stInYcp
quote.Volume = stInVolume
Set STOCK = Nothing
Set quote = Nothing
What is the equivalent of CreateObject in C#?. I try to add references to com object but i can't find any com object as Broker.Application or amibroker
If you are using .net 4 or later, and therefore can make use of dynamic, you can do this quite simply. Here's an example that uses the Excel automation interface.
Type ExcelType = Type.GetTypeFromProgID("Excel.Application");
dynamic ExcelInst = Activator.CreateInstance(ExcelType);
ExcelInst.Visible = true;
If you can't use dynamic then it's much more messy.
Type ExcelType = Type.GetTypeFromProgID("Excel.Application");
object ExcelInst = Activator.CreateInstance(ExcelType);
ExcelType.InvokeMember("Visible", BindingFlags.SetProperty, null,
ExcelInst, new object[1] {true});
Trying to do very much of that will sap the lifeblood from you.
COM is so much easier if you can use early bound dispatch rather than late bound as shown above. Are you sure you can't find the right reference for the COM object?
If you use .NET Framework 4.0 and above, you can use this pattern:
public sealed class Application: MarshalByRefObject {
private readonly dynamic _application;
// Methods
public Application() {
const string progId = "Broker.Application";
_application = Activator.CreateInstance(Type.GetTypeFromProgID(progId));
}
public Application(dynamic application) {
_application = application;
}
public int Import(ImportType type, string path) {
return _application.Import((short) type, path);
}
public int Import(ImportType type, string path, string defFileName) {
return _application.Import((short) type, path, defFileName);
}
public bool LoadDatabase(string path) {
return _application.LoadDatabase(path);
}
public bool LoadLayout(string path) {
return _application.LoadLayout(path);
}
public int Log(ImportLog action) {
return _application.Log((short) action);
}
public void Quit() {
_application.Quit();
}
public void RefreshAll() {
_application.RefreshAll();
}
public void SaveDatabase() {
_application.SaveDatabase();
}
public bool SaveLayout(string path) {
return _application.SaveLayout(path);
}
// Properties
public Document ActiveDocument {
get {
var document = _application.ActiveDocument;
return document != null ? new Document(document) : null;
}
}
public Window ActiveWindow {
get {
var window = _application.ActiveWindow;
return window != null ? new Window(window) : null;
}
}
public AnalysisDocs AnalysisDocs {
get {
var analysisDocs = _application.AnalysisDocs;
return analysisDocs != null ? new AnalysisDocs(analysisDocs) : null;
}
}
public Commentary Commentary {
get {
var commentary = _application.Commentary;
return commentary != null ? new Commentary(commentary) : null;
}
}
public Documents Documents {
get {
var documents = _application.Documents;
return documents != null ? new Documents(documents) : null;
}
}
public string DatabasePath {
get { return _application.DatabasePath; }
}
public bool Visible {
get { return _application.Visible != 0; }
set { _application.Visible = value ? 1 : 0; }
}
public string Version {
get { return _application.Version; }
}
}
}
Next you must wrap all AmiBroker OLE Automation classes. For example wrap Commentary class:
public sealed class Commentary : MarshalByRefObject {
// Fields
private readonly dynamic _commentary;
// Methods
internal Commentary(dynamic commentary) {
_commentary = commentary;
}
public void Apply() {
_commentary.Apply();
}
public void Close() {
_commentary.Close();
}
public bool LoadFormula(string path) {
return _commentary.LoadFormula(path);
}
public bool Save(string path) {
return _commentary.Save(path);
}
public bool SaveFormula(string path) {
return _commentary.SaveFormula(path);
}
}
Here's a snippet from the C# code I used to automate Amibroker (from when I went down that path). You'll need to reference System.Runtime.Interopservices
System.Type objType = System.Type.GetTypeFromProgID("Broker.Application");
dynamic comObject = System.Activator.CreateInstance(objType);
comObject.Import(0, fileName, "default.format");
comObject.RefreshAll();
Typing a dot won't bring up the comObject internal methods, though.
All I can say about this method is - it works, like a charm, but stay away from it, like David said. I got my inspiration for this method from:
http://www.codeproject.com/Articles/148959/How-the-new-C-dynamic-type-can-simplify-access-to
For another angle of attack, you may want to check out (I think this is early binding):
http://adamprescott.net/2012/04/05/net-vb6-interop-tutorial/
Hope at least some of this help you. I've used both these methods with Amibroker and C#, but I ended up leaving them behind. COM and Amibroker don't mix well. Even TJ says so.
Good luck anyway.
ami2py will read AmiBroker data into python. The current version is .0.8.1 WARNING: It only provides day resolution on data.
The following few lines of code will read a symbol from AmiBroker into a pandas df
import pandas
import ami2py
folder='C:/Program Files/AmiBroker/Databases/StockCharts'
symbol='indu'
df = pandas.DataFrame()
symbolData = ami2py.AmiDataBase(folder).get_dict_for_symbol(symbol)
for z in ['Year', 'Month', 'Day', 'Open', 'High', 'Low', 'Close', 'Volume'] :
df[symbol+':'+z] = symbolData[z]
print(df.describe())
When I use
SelectSingleNode("//meta[#name='keywords']")
it doesn't work, but when I use the same case that used in original document it works good:
SelectSingleNode("//meta[#name='Keywords']")
So the question is how can I set case ignoring?
If the actual value is an unknown case, I think you have to use translate. I believe it's:
SelectSingleNode("//meta[translate(#name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='keywords']")
This is the hack, but it's the only option in XPath 1.0 (except the opposite to upper-case).
If you need a more comprehensive solution, you can write an extension function for the XPath processor which will perform a case insensitive comparison. It is quite a bit of code, but you only write it once.
After implementing the extension you can write your query as follows
"//meta[#name[Extensions:CaseInsensitiveComparison('Keywords')]]"
Where Extensions:CaseInsensitiveComparison is the extension function implemented in the sample below.
NOTE: this is not well tested I just threw it together for this response so the error handling etc. is non-existent!
The following is the code for the custom XSLT Context which provides one or more extension functions
using System;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Xml;
using HtmlAgilityPack;
public class XsltCustomContext : XsltContext
{
public const string NamespaceUri = "http://XsltCustomContext";
public XsltCustomContext()
{
}
public XsltCustomContext(NameTable nt)
: base(nt)
{
}
public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] ArgTypes)
{
// Check that the function prefix is for the correct namespace
if (this.LookupNamespace(prefix) == NamespaceUri)
{
// Lookup the function and return the appropriate IXsltContextFunction implementation
switch (name)
{
case "CaseInsensitiveComparison":
return CaseInsensitiveComparison.Instance;
}
}
return null;
}
public override IXsltContextVariable ResolveVariable(string prefix, string name)
{
return null;
}
public override int CompareDocument(string baseUri, string nextbaseUri)
{
return 0;
}
public override bool PreserveWhitespace(XPathNavigator node)
{
return false;
}
public override bool Whitespace
{
get { return true; }
}
// Class implementing the XSLT Function for Case Insensitive Comparison
class CaseInsensitiveComparison : IXsltContextFunction
{
private static XPathResultType[] _argTypes = new XPathResultType[] { XPathResultType.String };
private static CaseInsensitiveComparison _instance = new CaseInsensitiveComparison();
public static CaseInsensitiveComparison Instance
{
get { return _instance; }
}
#region IXsltContextFunction Members
public XPathResultType[] ArgTypes
{
get { return _argTypes; }
}
public int Maxargs
{
get { return 1; }
}
public int Minargs
{
get { return 1; }
}
public XPathResultType ReturnType
{
get { return XPathResultType.Boolean; }
}
public object Invoke(XsltContext xsltContext, object[] args, XPathNavigator navigator)
{
// Perform the function of comparing the current element to the string argument
// NOTE: You should add some error checking here.
string text = args[0] as string;
return string.Equals(navigator.Value, text, StringComparison.InvariantCultureIgnoreCase);
}
#endregion
}
}
You can then use the above extension function in your XPath queries, here is an example for our case
class Program
{
static string html = "<html><meta name=\"keywords\" content=\"HTML, CSS, XML\" /></html>";
static void Main(string[] args)
{
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
XPathNavigator nav = doc.CreateNavigator();
// Create the custom context and add the namespace to the context
XsltCustomContext ctx = new XsltCustomContext(new NameTable());
ctx.AddNamespace("Extensions", XsltCustomContext.NamespaceUri);
// Build the XPath query using the new function
XPathExpression xpath =
XPathExpression.Compile("//meta[#name[Extensions:CaseInsensitiveComparison('Keywords')]]");
// Set the context for the XPath expression to the custom context containing the
// extensions
xpath.SetContext(ctx);
var element = nav.SelectSingleNode(xpath);
// Now we have the element
}
}
This is how I do it:
HtmlNodeCollection MetaDescription = document.DocumentNode.SelectNodes("//meta[#name='description' or #name='Description' or #name='DESCRIPTION']");
string metaDescription = MetaDescription != null ? HttpUtility.HtmlDecode(MetaDescription.FirstOrDefault().Attributes["content"].Value) : string.Empty;
Alternatively use the new Linq syntax which should support case insensitive matching:
node = doc.DocumentNode.Descendants("meta")
.Where(meta => meta.Attributes["name"] != null)
.Where(meta => string.Equals(meta.Attributes["name"].Value, "keywords", StringComparison.OrdinalIgnoreCase))
.Single();
But you have to do an ugly null check for the attributes in order to prevent a NullReferenceException...