【问题标题】:Is there any way to execute code once in a ASP.NET Web API REST service?有没有办法在 ASP.NET Web API REST 服务中执行一次代码?
【发布时间】:2020-12-02 23:27:09
【问题描述】:

我有一个 ASP.NET Web API REST 服务,我想在服务第一次启动时执行一些代码,而不是每次从我的 ASP.NET MVC 应用程序请求/调用 Web api 方法时。

我想这样做是因为我想初始化一个 EventLog,然后用它在 windows 事件查看器中创建条目。

有什么简单的方法吗?

更新: 正如 Jonhatan 在他的回答中建议的那样,我在 global.asax.cs 中创建了一个方法:

Global.asax.cs

namespace MyWebAPIApp
{
    public class WebApiApplication : System.Web.HttpApplication
    {
        public MyLog _myLog;

        protected void Application_Start()
        {
             // Here some stuff

             SetupEventLogging();
        }

        private void SetupEventLogging()
        {
            if (!EventLog.SourceExists("MyWebApiLog"))
            {
                EventLog.CreateEventSource("MyWebApiLog", "MyWebApiLogLog");
            }

            EventLog eventLog = new EventLog();
            eventLog.Source = "MyWebApiLog";
            eventLog.Log = "MyWebApiLog";
           
            _myLog = new MyLog(eventLog, "MyWebApiService");
        }
    }
}

控制器

namespace MyWebAPIApp.Controllers
{
    public class MyController : ApiController
    {
        public void GetAll()
        {
            _myLog.Success("All records read");
        }
    }
}

但是现在如果我创建一个全局变量 _myLog,我如何从我的 Controller 中的所有方法访问这个变量以执行 _myLog.Error(...) 或 _myLog.Success(...)?

【问题讨论】:

    标签: c# asp.net-web-api asp.net-web-api2 event-log


    【解决方案1】:

    您通常会在 global.asax.cs 中的 ApplicationStart 方法中执行此操作:

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
    
            SetupLogging(); // do something in here / wire up your flavour of logging
        }
    

    通常,模式是:

    1. 在应用启动时设置您的日志记录 - 这是您设置数据库连接以存储日志等的地方
    2. 只要您想写入日志,请在整个代码中调用静态 logger.Write 方法。

    我使用 Microsoft.Practices.EnterpriseLibrary.Logging,但我认为 Serilog 或 Log4Net 现在可能是两种更常见的框架。

    所以,在我的 global.asax.cs 中,SetupLogging() 方法是:

        private static void SetupLogging()
        {
    
            var configurationSource = ConfigurationSourceFactory.Create();
            DatabaseFactory.SetDatabaseProviderFactory(new DatabaseProviderFactory(configurationSource));
    
            var logWriterFactory = new LogWriterFactory(configurationSource);
            Logger.SetLogWriter(logWriterFactory.Create());
    
            var daysToKeepLogsInDb = int.Parse(ConfigurationManager.AppSettings["DaysToKeepLogsInDb"]);
            CustomLogger.PurgeLogs(daysToKeepLogsInDb); // only keep last 90 etc days of event logging in the db
    
            CustomLogger.Write("Application Starting", TraceEventType.Information);
        }
    

    基本上只是框架需要“开始”的东西,以及一些自定义清理。然后我有一个CustomLogger 类来帮助按照我想要的方式编写条目,运行自定义存储过程来清理旧日志等:

     using Microsoft.Practices.EnterpriseLibrary.Logging;
     using System;
     using System.Collections.Generic;
     using System.Configuration;
     using System.Data;
     using System.Data.SqlClient;
     using System.Diagnostics;
     
     namespace MyApplication.Helpers
     {
         public class CustomLogger
         {
             private static readonly ICollection<string> EmptyCategoriesList = new List<string>(0);
             private const string LogTitle = "MyApplication Name";
     
             public static void Write(object message)
             {
                 Write(message, TraceEventType.Error);
             }
     
             public static void Write(object message, TraceEventType severity)
             {
                 Logger.Write(message, EmptyCategoriesList, -1, 1, severity, LogTitle);
             }
     
             public static void PurgeLogs(int keepLastXDays)
             {
     
                 var connectionString = ConfigurationManager.ConnectionStrings["MyLoggingConnectionString"].ConnectionString;
     
                 using (var con = new SqlConnection(connectionString))
                 {
                     using (var command = new SqlCommand("PurgeLogs", con)) // custom stored procedure
                     {
                         var dateTo = DateTime.Now.AddDays(keepLastXDays * -1);
     
                         command.CommandType = CommandType.StoredProcedure;
                         command.Parameters.Add(new SqlParameter("@dateTo", dateTo));
                         command.Parameters.Add(new SqlParameter("@title", LogTitle));
     
                         con.Open();
                         command.ExecuteNonQuery();
                         con.Close(); // technically not required because in using, but leaving in case this block gets copy-pasted out of here
                     }
                 }
             }
         }
     }
    

    然后,在我的代码(控制器、助手等)中,我通过自定义记录器中的静态方法写入日志:

        public static void EndSession(Session session)
        {
            try
            {
                Logon.DoLogoff(session);
            }
            catch (Exception exception)
            {
                CustomLogger.Write(exception);
                throw new Exception("Error ending session.");
            }
        }
    

    如果您使用依赖注入来执行此操作,它将(特别是)允许您更轻松地更换日志框架,并允许您更轻松地进行单元测试。但是您必须在应用程序和记录器之间创建另一个“层”以进一步抽象关系。您应该阅读依赖注入,因为它通常值得使用。

    【讨论】:

    • 好的,但是在 SetupLogging 中我应该以某种方式创建一个全局变量,以便控制器中的所有方法都可以访问它以写入事件日志。查看我的更新。
    • @Ralph 你真的应该考虑设置依赖注入,在像这样的旧技术中这样做有点手动,但完全值得。
    • @DavidG 看起来很有趣。你能放一些代码sn-p吗?
    • @Ralph 您通常不需要全局变量,只要您的日志记录方法是静态的。我在上面的答案中提供了更多细节
    • 好的,Web api 项目文件夹结构中放置这个 CustomLogger 类的最佳位置在哪里?
    【解决方案2】:

    但是现在如果我创建一个全局变量 _myLog,我如何从我的 Controller 中的所有方法访问这个变量以执行 _myLog.Error(...) 或 _myLog.Success(...)?

    _myLog设为静态并引用它WebApiApplication._myLog,其中WebApiApplicationglobal.asax.cs中定义的应用程序类。

    我宁愿创建一些带有 MyLog 静态属性的静态类:

    public static class LogManager
    {
        public static MyLog Logger;
    }
    

    然后在global.asax.cs 中放入SetupEventLogging()

    LogManager.Logger = new MyLog(eventLog, "MyWebApiService");

    【讨论】:

      猜你喜欢
      • 2020-06-12
      • 1970-01-01
      • 2019-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-07
      • 2021-05-07
      相关资源
      最近更新 更多