একটি ডাটাবেসে asp.net ওয়েবপি 2 অনুরোধ এবং প্রতিক্রিয়ার মূল লগ ইন করতে হবে


103

আমি আইআইএস-এ হোস্ট করা মাইক্রোসফ্ট Asp.net ওয়েবএপিআই 2 ব্যবহার করছি। আমি খুব সহজেই অনুরোধ বডি (এক্সএমএল বা জেএসওএন) এবং প্রতিটি পোস্টের জন্য প্রতিক্রিয়া বডিটি লগ করতে চাই।

এই প্রকল্প বা পোস্টার প্রক্রিয়াজাতকরণের বিষয়ে বিশেষ কিছু নেই। এনলগ, এলমাহ, লগ 4 নেট, বা ওয়েব এপিআই-র বিল্ট-ইন ট্রেসিং বৈশিষ্ট্যগুলির মতো লগিং ফ্রেমওয়ার্কগুলি ব্যবহার করতে আগ্রহী না যতক্ষণ না এটি করা প্রয়োজন।

আমি কেবল আমার লগিং কোডটি কোথায় রাখব এবং কীভাবে আসন্ন এবং বহির্গামী অনুরোধ এবং প্রতিক্রিয়া থেকে আসল জেএসএন বা এক্সএমএল পাবেন তা জানতে চাইছি।

আমার নিয়ামক পোস্ট পদ্ধতি:

public HttpResponseMessage Post([FromBody])Employee employee)
{
   if (ModelState.IsValid)
   {
      // insert employee into to the database
   }

}

আপনি কি কোনও বিশেষ ক্রিয়াকলাপ, একটি সেট, বা একটি নির্দিষ্ট নিয়ামকটিতে আপনার সমস্ত ক্রিয়াকলাপের জন্য অনুরোধ / প্রতিক্রিয়া লগ করতে খুঁজছেন?
এলবি 2

শুধুমাত্র পোস্ট লগ করতে আগ্রহী। (ক) পোস্টের সময় (খ) এক্সএমএল বা জসন এর বডি পোস্ট (সি) প্রতিক্রিয়া (এক্সএমএল বা জসন সামগ্রী)
এইচটিপিপি

যে কারণটি আমি জিজ্ঞাসা করছিলাম তা হ'ল কোডটি সরাসরি কর্মে রাখা হয় কিনা বা সমস্ত ক্রিয়াকলাপের জেনেরিক সমাধান। আমার উত্তর নীচে দেখুন।
এলবি 2

এফওয়াইআই আমি এএসপিএনটি সরিয়ে দিয়েছিলাম কারণ এটি এই প্রশ্নটির উপর নির্ভর করে না
ডালোরজো

ফাইলার তৈরি করা একটি বিকল্প নয়?
প্রেরাক কে

উত্তর:


192

আমি একটি ব্যবহার করার সুপারিশ করব DelegatingHandler। তারপরে আপনার নিয়ামকদের কোনও লগিং কোড সম্পর্কে আপনাকে চিন্তার প্রয়োজন হবে না।

public class LogRequestAndResponseHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Content != null)
        {
            // log request body
            string requestBody = await request.Content.ReadAsStringAsync();
            Trace.WriteLine(requestBody);
        }
        // let other handlers process the request
        var result = await base.SendAsync(request, cancellationToken);

        if (result.Content != null)
        {
            // once response body is ready, log it
            var responseBody = await result.Content.ReadAsStringAsync();
            Trace.WriteLine(responseBody);
        }

        return result;
    }
}

কেবলমাত্র Trace.WriteLineআপনার লগিং কোডের সাথে প্রতিস্থাপন করুন এবং হ্যান্ডলারটি WebApiConfigএই জাতীয়ভাবে নিবন্ধ করুন :

config.MessageHandlers.Add(new LogRequestAndResponseHandler());

মেসেজ হ্যান্ডলারের সম্পূর্ণ মাইক্রোসফ্ট ডকুমেন্টেশন এখানে রয়েছে ।


3
task.Result.Contentআয় System.Net.Http.ObjectContent। পরিবর্তে কাঁচা এক্সএমএল / জসন পাওয়ার কোনও উপায় আছে?
পিসি

4
@ সফটওয়্যার ফ্যাক্টর: ContinueWithএবং Resultবিপজ্জনক এপিআই। awaitপরিবর্তে এটি ব্যবহার করা আরও ভাল হবে ,var result = await base.SendAsync(request, cancellationToken); var resposeBody = await response.Content.ReadAsStringAsync(); Trace.WriteLine(responseBody); return response;
স্টিফেন ক্লিয়ারি

9
এটি একটি দুর্দান্ত সমাধান, তবে প্রতিক্রিয়ার কোনও শরীরে না থাকলে এটি ত্রুটি ছুঁড়ে দেবে। কিন্তু না না সহজ যথেষ্ট ফিক্স :) পরীক্ষা করুন এবং
buddybubble

6
কলটি কি await request.Content.ReadAsStringAsync();অনুরোধের স্ট্রিমটি ইতিমধ্যে কিছু নির্দিষ্ট পরিস্থিতিতে পড়েছে তা বলে ত্রুটি না ঘটায়?
গাভিন

6
যদি ডেলিগেটিং হ্যান্ডলার অনুরোধের মূল অংশটি পড়ে থাকে তবে এটি কি এটি প্রকৃত টার্মিনাল হ্যান্ডলারের (যেমন এমভিসি / ওয়েবপি) কাছে অনুপলব্ধ করে দেবে না?
এলবি 2

15

প্রতিটি ওয়েবএপিআই পদ্ধতি কলগুলির জন্য অনুরোধ / প্রতিক্রিয়া লগিংকে সাধারণভাবে পরিচালনা করার জন্য একাধিক পদ্ধতি রয়েছে:

  1. ActionFilterAttribute: ActionFilterAttributeলগিং সক্ষম করার জন্য কেউ কাস্টম লিখতে এবং নিয়ন্ত্রণকারী / ক্রিয়া পদ্ধতিগুলি সাজাতে পারে।

    কন: আপনার প্রতিটি নিয়ামক / পদ্ধতিগুলি সাজাতে হবে (তবুও আপনি এটি বেস কন্ট্রোলারের উপর করতে পারেন, তবে তবুও এটি ক্রস কাটানোর উদ্বেগের সমাধান করে না।

  2. ওভাররাইড BaseControllerএবং সেখানে লগিং পরিচালনা করুন।

    কন: আমরা কাস্টম বেস নিয়ন্ত্রকের কাছ থেকে উত্তরাধিকারীদের উত্তরাধিকারী হওয়ার / প্রত্যাশা করছি for

  3. ব্যবহার DelegatingHandler

    সুবিধা: আমরা এই পদ্ধতির সাথে এখানে নিয়ামক / পদ্ধতিটিকে স্পর্শ করছি না। ডেলিগেটিং হ্যান্ডলার বিচ্ছিন্ন হয়ে বসে এবং অনুরোধ / প্রতিক্রিয়া লগিং করুণভাবে পরিচালনা করে।

আরও নির্লিপ্ত নিবন্ধের জন্য, এই http://weblogs.asp.net/fredriknormen/log-message-request-and-response-in-asp-net-webapi দেখুন


আপনি নিম্নরূপ যেকোন অ্যাকশনফিলার নির্ধারণ করতে সক্ষম হবেন: পাবলিক স্ট্যাটিক ক্লাস ওয়েবএপিসিফিনিফিগ {পাবলিক স্ট্যাটিক শূন্য রেজিস্টার (এইচটিপিপি কনফিগারেশন কনফিগারেশন) {// ওয়েব এপিআই কনফিগারেশন এবং পরিষেবাদি কনফিগারেশন। ফিল্টারস।আপনি (নতুন মাইফিল্টার ()) // ওয়েব এপিআই রুট কনফিগারেশন (); config.Routes.MapHttpRoute (নাম: "DefaultApi", রুট টেম্পলেট: "এপিআই / {নিয়ামক} / {id {", ডিফল্ট: নতুন {আইডি = রুটপ্যারামিটার .চ্ছিক}); }}
মিকা কারজুনেন

11

আপনার কাছে থাকা বিকল্পগুলির মধ্যে একটি হ'ল একটি অ্যাকশন ফিল্টার তৈরি করা এবং এটির সাথে আপনার ওয়েবএপিসিট্রোলার / এপিএমথোড সজ্জিত করা।

ফিল্টার অ্যাট্রিবিউট

public class MyFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (actionContext.Request.Method == HttpMethod.Post)
            {
                var postData = actionContext.ActionArguments;
                //do logging here
            }
        }
    }

WebApi নিয়ামক

[MyFilterAttribute]
public class ValuesController : ApiController{..}

অথবা

[MyFilterAttribute]
public void Post([FromBody]string value){..}

আশাকরি এটা সাহায্য করবে.


আমি এই পদ্ধতির পছন্দ করি তবে প্রতিক্রিয়া পেতে আমাকে তার পরিবর্তে অনঅ্যাকশনএকসকেটেডকে ওভাররাইড করতে হবে। সমস্যাটি হ'ল অনুরোধটি এই মুহুর্তে এক্সএমএল বা জসন না হয়ে ইতিমধ্যে আমার পোকোতে রূপান্তরিত হয়েছে। কোন চিন্তা?
ব্যবহারকারী 2315985

মূলত আমি বলতে চাইছিলাম, অন্যাকশনএক্সেকুটিংয়ে ডেটা লগ করুন এবং তারপরে সহজ পোস্টটিকে তার কাজটি করতে দিন। আপনার প্রশ্নটি থেকে আমি বুঝতে পেরেছি যে আপনি প্রতিটি পোস্টের জন্য ডেটা লগ করতে চান।
প্রেরাক কে

3
আমি অনুরোধ এবং প্রতিক্রিয়ার তথ্য উভয়ই লগ করতে চাইছি প্রতিবার কেউ পোস্ট করুন।
ব্যবহারকারী 2315985

2
প্রতিক্রিয়া পেতে এবং এটি লগ করতে আপনি "অ্যাকশনএক্সেকিউটেড এবং" (ক্রিয়াএক্সেকিউটেড কনটেক্সট.অ্যাকশনকন্টেক্সট.রেস্পোনস.কন্টেন্ট অবজেক্ট কনটেন্ট হিসাবে) ব্যবহার করতে পারেন। মূল্য।
প্রেরাক কে

আমি কীভাবে অনুরোধটি অনঅ্যাকশনএক্সেকটেডের মধ্যে থেকে পাব?
ব্যবহারকারী 2315985

3

অনুরোধ বার্তায় অ্যাক্সেস পাওয়া সহজ। আপনার বেস ক্লাসে ApiController.Requestসম্পত্তি রয়েছে , যা নাম হিসাবে প্রস্তাবিত, পার্স আকারে অনুরোধটি অন্তর্ভুক্ত করে। আপনি যা যা লগইন করতে চান এবং আপনার লগিং সুবিধার কাছে এটি যা যা কিছু হোক না কেন এটির জন্য আপনি কেবল এটি পরীক্ষা করে দেখুন। এই কোডটি আপনি নিজের ক্রিয়াকলাপের শুরুতে রাখতে পারেন, যদি আপনার এটির প্রয়োজন কেবলমাত্র এক বা মুষ্টিমেয়।

আপনার যদি এটি সমস্ত ক্রিয়ায় করা দরকার (যার অর্থ একটি পরিচালনযোগ্য মুষ্টিমেয়ের চেয়ে বেশি), তবে আপনি যা করতে পারেন তা হ'ল .ExecuteAsyncআপনার নিয়ামকের জন্য প্রতিটি ক্রিয়াকলাপ ক্যাপচার করার পদ্ধতিটিকে ওভাররাইড করুন।

public override Task<HttpResponseMessage> ExecuteAsync(
    HttpControllerContext controllerContext,
    CancellationToken cancellationToken
)
{
    // Do logging here using controllerContext.Request
    return base.ExecuteAsync(controllerContext, cancellationToken);
}

আমি এটি করছি, এবং আমি এখনও এটি বেঞ্চমার্ক করতে পারিনি, কেবল আমার অন্তর্নিহিততা আমাকে বলে যে এটি খুব ধীর হতে পারে?
মার্কাস

কেন আপনি মনে করেন এটি ধীর হবে? ExecuteAsyncকাঠামো দ্বারা যা ডাকা হয়, এবং বেস কন্ট্রোলার শ্রেণি 'বাস্তবায়নই আসলে কার্য সম্পাদন করে। এটি ইতিমধ্যে ঘটছে সম্পাদনের অংশ হিসাবে কেবল আপনার লগিংয়ে কল করছে। তাদের এখানে কেবল পেনাল্টিই আসল লগিং করার সময়।
এলবি 2

না, আমি বলতে চাই, প্রতিটি অনুরোধ লগ করতে যেমন 'খুব ধীর'।
মারকাস

2
ঠিক আছে, এটি প্রয়োজনীয়তার একটি প্রশ্ন এবং এটি অপের দ্বারা বর্ণিত প্রয়োজনীয়তা। এটি সাইট পরিচালনা করে আয়তনের প্রশ্ন, লগিং সুবিধার কার্যকারিতা ইত্যাদি That's এটি ওপি পোস্টের বাইরে beyond
LB2

0

এটি বেশ পুরানো থ্রেড বলে মনে হচ্ছে তবে অন্য সমাধান ভাগ করে নেওয়াও বেশ কঠিন।

আপনি এই পদ্ধতিটি আপনার গ্লোবাল.অ্যাক্সেস ফাইলটিতে যুক্ত করতে পারেন যা এইচটিটিপি অনুরোধ শেষ হওয়ার পরে প্রতি ট্রিগার হবে।

void Application_EndRequest(Object Sender, EventArgs e)
    {
        var request = (Sender as HttpApplication).Request;
        var response = (Sender as HttpApplication).Response;

        if (request.HttpMethod == "POST" || request.HttpMethod == "PUT")
        {


            byte[] bytes = request.BinaryRead(request.TotalBytes);
            string body = Encoding.UTF7.GetString(bytes);
            if (!String.IsNullOrEmpty(body))
            {


                // Do your logic here (Save in DB, Log in IIS etc.)
            }
        }
    }

0

এটি সত্যই পুরানো বিষয় তবে আমি এই জিনিসটি করতে অনেক সময় ব্যয় করেছি (ইন্টারনেট অনুসন্ধান করুন) তাই আমি এখানে আমার সমাধানটি পোস্ট করব।

ধারণা

  1. ইনবাউন্ড অনুরোধ ট্র্যাকিংয়ের জন্য এপিকন্ট্রোলার পদ্ধতির এক্সিকিউটআসেন্সকে ওভাররাইড করুন, আমার সমাধানে আমি আমার প্রকল্পের এপিআই কন্ট্রোলারগুলির পিতামাতা হিসাবে বেস_অপি কন্ট্রোলার তৈরি করি।
  2. এপিআই কন্ট্রোলারের আউটবাউন্ড প্রতিক্রিয়া ট্র্যাক করতে System.Web.Http.Filters.ActionFilterAttribute ব্যবহার করুন
  3. *** (অতিরিক্ত) *** ব্যতিক্রম ঘটলে লগ করার জন্য System.Web.Http.Filters.ExceptionFilterAttribute ব্যবহার করুন।

1. MyController.cs

    [APIExceptionFilter]  // use 3.
    [APIActionFilter]     // use 2.
    public class Base_APIController : ApiController
    {
        public   bool  IsLogInbound
        {
            get
            { return   ConfigurationManager.AppSettings["LogInboundRequest"] =="Y"? true:false ;     }
        }
        /// <summary>
        /// for logging exception
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public override Task<HttpResponseMessage> ExecuteAsync(
         HttpControllerContext controllerContext,
         CancellationToken cancellationToken
         )
        {
            // Do logging here using controllerContext.Request
            // I don't know why calling the code below make content not null Kanit P.
            var content = controllerContext.Request.Content.ReadAsStringAsync().Result.ToString(); // keep request json content
             // Do your own logging!
            if (IsLogInbound)
            {
                try
                {
                    ErrLog.Insert(ErrLog.type.InboundRequest, controllerContext.Request,
                         controllerContext.Request.RequestUri.AbsoluteUri
                         , content);
                }
                catch (Exception e) { }
            }

            // will not log err when go to wrong controller's action (error here but not go to APIExceptionFilter)
            var t = base.ExecuteAsync(controllerContext, cancellationToken);
            if (!t.Result.IsSuccessStatusCode)
            { 
            }
            return t;

        }

2. APIActionFilter.cs

    public class APIActionFilter : System.Web.Http.Filters.ActionFilterAttribute
    {
        public bool LogOutboundRequest
        {
            get
            { return ConfigurationManager.AppSettings["LogInboundRequest"] == "Y" ? true : false; }
        }

        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            try {

                var returndata = actionExecutedContext.Response.Content.ReadAsStringAsync().Result.ToString(); 
             //keep Json response content
             // Do your own logging!
                if (LogOutboundRequest)
                {
                    ErrLog.Insert(ErrLog.type.OutboundResponse, actionExecutedContext.Response.Headers,
                       actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerName
                      + "/"
                      + actionExecutedContext.ActionContext.ActionDescriptor.ActionName
                      , returndata );
                }
            } catch (Exception e) {

            }
     

        } 
    }
}

3. APIExceptionFilter.cs

    public class APIExceptionFilter : ExceptionFilterAttribute
    {
    public bool IsLogErr
    {
        get
        { return ConfigurationManager.AppSettings["LogExceptionRequest"] == "Y" ? true : false; }
    }


    public override void OnException(HttpActionExecutedContext context)
    {
        try
        { 
            //Do your own logging!
            if (IsLogErr)
            {
                ErrLog.Insert(ErrLog.type.APIFilterException, context.Request,
                    context.ActionContext.ControllerContext.ControllerDescriptor.ControllerName
                    + "/"
                    + context.ActionContext.ActionDescriptor.ActionName
                    , context.Exception.ToString() + context.Exception.StackTrace);
            }
        }catch(Exception e){

        }

        if (context.Exception is NotImplementedException)
        {
            context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
        }
        else {
            context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError);

        }
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.