Reading a file in MVC 6 - c#

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.

Related

Obtain Assembly attributes from unloaded executable

I am attempting to retrieve the typical AssemblyInfo attributes from an executable file, but not from the currently executing assembly. I wish to 'look into' a program file (.exe) elsewhere on the drive that I have written in C#.NET and check the AssemblyProduct string.
This is fairly easy and straightforward when you're looking for this information from the currently executing assembly. However, apparently not so much when you attempt to pull it from an unloaded assembly.
When I use the following code, it returns "Microsoft® .NET Framework" instead of the Product name that I put in my AssemblyInfo.cs file.
Note: I use the System.Reflection.AssemblyName object to pull the version info e.g:AssemblyName.GetAssemblyName(pathToAssembly) and this works correctly, but I'm unable to pull my assembly's attributes using that class or by any means I've tried thus far. Is there some other special class, or what am I missing or doing incorrectly here?
public static string GetAppProdIDFromPath(string pathToForeignAssembly)
{
var atts = GetForeignAssemblyAttributes(pathToForeignAssembly);
var id = string.Empty;
foreach (var att in atts)
{
if (att.GetType() == typeof(AssemblyProductAttribute))
{
id = ((AssemblyProductAttribute)att).Product;
}
}
return id;
}
private static object[] GetForeignAssemblyAttributes(string pathToAssembly)
{
if(File.Exists(pathToAssembly))
{
try
{
var assm = System.Reflection.Assembly.LoadFrom(pathToAssembly);
return assm.GetType().Assembly.GetCustomAttributes(false);
}
catch(Exception ex)
{
// logger etc
}
}
else
{
throw...
}
return null;
}
As Duncanp mentioned, there is a bug in my code. Posting it for clarity and for anyone down the road who looks for the same solution:
public static string GetAppProdIDFromPath(string pathToForeignAssembly)
{
var atts = GetForeignAssemblyAttributes(pathToForeignAssembly);
var id = string.Empty;
foreach (var att in atts)
{
if (att.GetType() == typeof(AssemblyProductAttribute))
{
id = ((AssemblyProductAttribute)att).Product;
}
}
return id;
}
private static object[] GetForeignAssemblyAttributes(string pathToAssembly)
{
if(File.Exists(pathToAssembly))
{
try
{
var assm = System.Reflection.Assembly.LoadFrom(pathToAssembly);
return assm.GetCustomAttributes(false); // fixed line
}
catch(Exception ex)
{
// logger etc
}
}
else
{
throw...
}
return null;
}

Amazon S3 SDK is not allowing me use the GetObjectMetadata. It only allows me use GetObjectMetadataAsync

I am using Amazon S3 sdk with .Net for a Xamarin project, and I need to check if an object exists in a bucket before doing something with it. I cannot use the Exists property on Amazon.S3.IO.S3FileInfo because I cannot use the Amazon.S3.IO namespace in my code for some reason. (using this would make life so much easier for me), so I am using the following code (which I got from the source code for S3FileInfo here)
public bool PackageExistsOnS3(string bucket, string key)
{
bool bucketExists;
return ExistsWithBucketCheck(out bucketExists, bucket, key);
}
private bool ExistsWithBucketCheck(out bool bucketExists, string bucket, string key)
{
bucketExists = true;
try
{
var request = new GetObjectMetadataRequest
{
BucketName = bucket,
Key = AWSS3Helper.EncodeKey(key)
};
((Amazon.Runtime.Internal.IAmazonWebServiceRequest) request).AddBeforeRequestHandler(AWSS3Helper
.FileIORequestEventHandler);
AmazonS3Client _client = new AmazonS3Client(_accessKey, _secretKey, _regionEndPoint);
// If the object doesn't exist then a "NotFound" will be thrown
// I DO NOT WANT TO USE THE METADATAASYNC VERSION HERE, I JUST WANT THE REGULAR VERSION BUT I CANNOT DO THAT
_client.GetObjectMetadataAsync();
//var test = _client.GetObjectMetadata;
return true;
}
catch (AmazonS3Exception e)
{
if (string.Equals(e.ErrorCode, "NoSuchBucket"))
{
bucketExists = false;
return false;
}
else if (string.Equals(e.ErrorCode, "NotFound"))
{
return false;
}
throw;
}
}
The code for AWSS3Helper is as below:
internal static class AWSS3Helper
{
internal static string EncodeKey(string key)
{
return key.Replace('\\', '/');
}
internal static string DecodeKey(string key)
{
return key.Replace('/', '\\');
}
internal static void FileIORequestEventHandler(object sender, RequestEventArgs args)
{
WebServiceRequestEventArgs wsArgs = args as WebServiceRequestEventArgs;
if (wsArgs != null)
{
string currentUserAgent = wsArgs.Headers[AWSSDKUtils.UserAgentHeader];
wsArgs.Headers[AWSSDKUtils.UserAgentHeader] = currentUserAgent + " FileIO";
}
}
}
Anyone know how I can avoid using this Asynchronous function? It will prevent me from returning a boolean value, and if I have to return something I would need use Await wherever this function is used meaning I would need to make every function that uses it an async function and I would really love to avoid the complications that come with doing that.
You can try to make your function async and use the await keyword before _client.GetObjectMetadataAsync(). If you dont do this, you get if the fuction is implememnted as async Task< T > a Task and not T in your case T is bool.
For IO connections it is standard now to use async functions in Dotnet to prevent your application to stop and waiting for response.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/

return a Json clickable list, from .netcore

net core development.
I'm trying to get a click-able list in a Json result
It seams [AllowJsonGet] is no longer possible in .net core,
So i try my way around it to code such a result.
The problem might be in my model definition or in my controller.
Maybe http urls should not be strings? (but then what should they be?)
Or should i add some extra verbs to Return Json(Clicklist) so that it knows of click-able urls ?
namespace Count.Models
{
public class ReadItems
{
public string filename;
public string url;
}
}
In count.Controllers.cs i wrote:
namespace Count.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
const string LogFolder = #"C:\Data\Count";
String[] result = Directory.GetFiles(LogFolder);
// GET api/values
[HttpGet]
// [AllowJsonGet] Dissalowed in .net core 2.0
public JsonResult Get()
{
List<Count.Models.ReadItems> clicklist = new List<Models.ReadItems>();
List<string> allFiles = System.IO.Directory.GetFiles(LogFolder).ToList();
allFiles.Reverse(); //newest on top
Models.ReadItems temp;
int i = 0;
foreach (string File in allFiles)
{
temp = new Models.ReadItems();
temp.filename = File.Replace(LogFolder + #"\\", ""); // remove real path
temp.url = "../../Api/values/" + i.ToString(); // <==not working
clicklist.Add(temp );
i++;
}
return Json(clicklist);
}

Change files using Roslyn

I'm trying to write a command line tool that modifies some code using Roslyn. Everything seems to go well: the solution is opened, the solution is changed, the Workspace.TryApplyChanges method returns true. However no actual files are changed on disk. What's up? Below is the top level code I'm using.
static void Main(string[] args)
{
var solutionPath = args[0];
UpdateAnnotations(solutionPath).Wait();
}
static async Task<bool> UpdateAnnotations(string solutionPath)
{
using (var workspace = MSBuildWorkspace.Create())
{
var solution = await workspace.OpenSolutionAsync(solutionPath);
var newSolution = await SolutionAttributeUpdater.UpdateAttributes(solution);
var result = workspace.TryApplyChanges(newSolution);
Console.WriteLine(result);
return result;
}
}
I constructed a short program using your code and received the results I expected - the problem appears to reside within the SolutionAttributeUpdater.UpdateAttributes method. I received these results using the following implementation with your base main and UpdateAnnotations-methods:
public class SolutionAttributeUpdater
{
public static async Task<Solution> UpdateAttributes(Solution solution)
{
foreach (var project in solution.Projects)
{
foreach (var document in project.Documents)
{
var syntaxTree = await document.GetSyntaxTreeAsync();
var root = syntaxTree.GetRoot();
var descentants = root.DescendantNodes().Where(curr => curr is AttributeListSyntax).ToList();
if (descentants.Any())
{
var attributeList = SyntaxFactory.AttributeList(
SyntaxFactory.SingletonSeparatedList(
SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("Cookies"), SyntaxFactory.AttributeArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.AttributeArgument(
SyntaxFactory.LiteralExpression(
SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(#"Sample"))
)})))));
root = root.ReplaceNodes(descentants, (node, n2) => attributeList);
solution = solution.WithDocumentSyntaxRoot(document.Id, root);
}
}
}
return solution;
}
}
It was tested using the following class in the sample solution:
public class SampleClass<T>
{
[DataMember("Id")]
public int Property { get; set; }
[DataMember("Id")]
public void DoStuff()
{
DoStuff();
}
}
And it resulted in the following Output:
public class SampleClass<T>
{
[Cookies("Sample")] public int Property { get; set; }
[Cookies("Sample")] public void DoStuff()
{
DoStuff();
}
}
If you take a look at the UpdateAttributes method I had to replace the nodes with ReplaceNodes and updated the solution by calling WithDocumentSyntaxRoot.
I would assume that either one of those two calls is missing or that nothing was changed at all - if you call workspace.TryApplyChanges(solution) you would still receive true as an Output.
Note that using multiple calls of root.ReplaceNode() instead of root.ReplaceNodes() can also result in an error since only the first update is actually used for the modified document - which might lead you to believe that nothing has changed at all, depending on the implementation.

ASP.NET MVC bundle scripts with translation

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

Categories