这是一个非常恼人的问题,我在堆栈和谷歌上进行了数十次搜索后无法解决这个问题。
我有一个Asp.Net Web应用程序,该解决方案本身有7个项目,其中一个是MVC项目,其中有如下所示的类。
using System;
using System.Web.Hosting;
namespace MyApp.Notifications
{
public class CustomEmails
{
private readonly string basePath = "C:\\Users\\MyUser\\MyAppName\\";
//HostingEnvironment.MapPath("~\\MyAppName")
//Server.MapPath("~")
//HostingEnvironment.ApplicationPhysicalPath("~");
//HostingEnvironment.ApplicationVirtualPath;
var subject = File.ReadAllText(basePath + "Notifications\\EmailTemplates\\EmailConfirmationEvent_Subject.txt");
//rest of classes code here
}
}
我可以在子文件夹中读取文本文件的唯一方法是对路径进行硬编码,如上所示。如您所见,我试图以编程方式检索应用程序的基本路径,然后将其添加到文件子路径中。
正如您在上面所看到的那样,在已注释的片段中,我尝试过很多事情。
对于初学者来说,永远不允许使用Server.MapPath,因为它始终是红色的,intellisense没有提供任何补救措施,谷歌搜索也没有提供太多其他服务,因为Server.MapPath是一种IIS方法。所有其他代码片段都没有返回任何内容。
我做错了什么?错误在哪里?是不是有一种标准的方式,所以无论是在开发机器上还是在主机虚拟机上,总是能获得正确的基本路径?
Per Darin的建议代码更新如下;
public class EmailEvents
{
private static readonly string basePath = CustomEmails.GetWebsiteRoot();
public class EmailAddressVerified : IEventHandler<EmailVerifiedEvent<UserAccount>>
{
public void Handle(EmailVerifiedEvent<UserAccount> evt)
{
dynamic smtp = new SmtpMessageDelivery();
var localAppPath = CustomEmails.GetWebsiteRoot();
var htmlBody = CustomEmails.GetHtmlEmailMessage(DomainClasses.Enums.EmailType.AccountConfirmation);
//{ProductionChange} --change the first parameter to false in production
htmlBody = CustomEmails.FillEmailPlaceholderText(false, htmlBody, evt.Account);
htmlBody = htmlBody.Replace(CustomEmails.EmailTextPlaceholders.HtmlFileKey, EncryptDecrypt.EncryptQueryString(Guid.NewGuid().ToString()));
var subject = File.ReadAllText(Path.Combine(basePath, "Notifications", "EmailTemplates", "EmailConfirmationEvent_Subject.txt"));
subject = subject.Replace(CustomEmails.EmailTextPlaceholders.ApplicationName, CustomEmails.EmailPlaceholderValues.ApplicationName);
var msg = new Message { To = evt.Account.Email, Subject = subject, Body = htmlBody };
smtp.Send(msg);
}
}
}
在上面的示例中,basePath始终没有,但localAppPath检索正确的路径。为什么类级私有变量不能检索路径?
答案 0 :(得分:0)
您可以声明一个变量,然后稍后在运行时填充该变量,只使用get使其成为只读,然后在属性中使用Server.MapPath。您不能像在类声明中那样在编译时执行此操作,因为它无法解决字符串const的问题,因为Server.MapPath无法解析为它可以使用的const,因为它几乎肯定会改变部署。
public class CustomEmails
{
private string _basePath = null;
private string BasePath
{
get
{
if ( _basePath == null )
{
this._basePath = Server.MapPath('...');
}
return _basePath;
}
}
在运行时,您对this.BasePath的第一个请求将使用MapPath(一次调用)填充私有变量,然后对该方法的所有后续调用将使用先前获取的值。
答案 1 :(得分:0)
您可以使用HostingEnvironment.MapPath
静态方法。
System.Web
程序集using System.Web.Hosting
使用指向网站根目录的单一方法编写一个类:
using System.Web.Hosting;
namespace MyApp.Notifications
{
public class CustomEmails
{
public static string GetWebsiteRoot()
{
// Get the website root
return HostingEnvironment.MapPath("~/");
}
}
}
备注:HostingEnvironment.MapPath
仅适用于ASP.NET虚拟主机。如果您尝试在外部使用它(例如单元测试或桌面应用程序),它将不会返回所需的结果。
在这种情况下,让您的函数作为网站根路径的依赖关系会好得多。这将使它们更容易进行单元测试。只有在Composition Root中,您才会使用正确的方法来注入路径。对于可以是HostingEnvironment.MapPath
方法的ASP.NET Web上下文。
此外,当您处理目录路径时,您完全想要使用Path.Combine
方法而不是您在问题中使用的+
运算符。例如:
string root = CustomEmails.GetWebsiteRoot();
string path = Path.Combine(root, "Notifications", "EmailTemplates", "EmailConfirmationEvent_Subject.txt");