डेटाइम पैरामीटर कैसे पास करें?


86

UTC तारीखों को Web API से कैसे पास करें?

पासिंग 2010-01-01ठीक काम करता है, लेकिन जब मैं एक यूटीसी तारीख 2014-12-31T22:00:00.000Z( जैसे समय घटक के साथ) पास करता हूं, तो मुझे HTTP 404 प्रतिक्रिया मिलती है। इसलिए

http://domain/api/controller/action/2012-12-31T22:00:00.000Z

404 त्रुटि प्रतिक्रिया देता है, जबकि

http://domain/api/controller/action/2012-12-31

ठीक काम करता है।

UTC तारीखों को वेब एपीआई में कैसे पास करें - या कम से कम दिनांक और समय निर्दिष्ट करें ?


2
क्या तिथि में ":" एक संदिग्ध है? इससे बचने की कोशिश करो। http://domain/api/controller/action/2012-12-31T22%3A00%3A00.000Z
श्क्लपक्ष

2
भागने से मदद नहीं मिलती। फिर भी 404.
निकोलोडियन

क्या आप डिबगिंग सक्षम कर सकते हैं ताकि यह पता लगाया जा सके कि अनुवाद स्ट्रिंग से तारीख तक विफल क्यों है? यह विचार करना है कि URL का उपयोग करके आपके द्वारा पास की गई तारीख का अनुवाद करने के लिए किस विधि का उपयोग किया जा रहा है DateTime- जो मुझे लगता है कि आपकी विधि पर डेटा प्रकार का सर्वोपरि है।
शालकपेश १६'१३

4
वह में स्वयं कर लूँगा। विधि .NET डेटाइम पैरामीटर की अपेक्षा करता है। मुझे लगता है कि यह हास्यास्पद है कि मैं समय घटक पारित नहीं कर सकता और ऐसा करने के लिए डॉक्स नहीं पा सकता हूं!
निकोलोडियन

2
जब आप कर रहे हों तब अपना समाधान पोस्ट करें। यह अन्य लोगों को समान समस्या होने में मदद कर सकता है। धन्यवाद।
श्क्लकेश

जवाबों:


33

समस्या दुगनी है:

1. .मार्ग में

डिफ़ॉल्ट रूप से, IIS सभी URI के साथ उन्हें स्थैतिक संसाधन के रूप में एक डॉट के साथ व्यवहार करता है, इसे वापस करने की कोशिश करता है और आगे की प्रक्रिया (वेब ​​एपीआई द्वारा) को पूरी तरह से छोड़ देता है। यह आपके Web.config अनुभाग में कॉन्फ़िगर किया गया है system.webServer.handlers: डिफ़ॉल्ट हैंडलर हैंडल path="*."। आपको इस pathविशेषता में अजीब सिंटैक्स के बारे में बहुत अधिक दस्तावेज नहीं मिलेंगे (रेगेक्स ने और अधिक अर्थ दिया होगा), लेकिन इसका स्पष्ट रूप से मतलब है "कुछ भी है जिसमें डॉट नहीं है" (और नीचे बिंदु 2 से कोई भी चरित्र)। इसलिए नाम में 'एक्सटेंशनलेस' ExtensionlessUrlHandler-Integrated-4.0

'शुद्धता' के क्रम में मेरी राय में कई समाधान संभव हैं:

  • उन मार्गों के लिए विशेष रूप से एक नया हैंडलर जोड़ें जो एक डॉट की अनुमति दें। डिफ़ॉल्ट से पहले इसे जोड़ना सुनिश्चित करें । ऐसा करने के लिए, सुनिश्चित करें कि आप पहले डिफ़ॉल्ट हैंडलर को हटा दें , और इसे अपने बाद वापस जोड़ें।
  • path="*."करने के लिए विशेषता बदलें path="*"। यह तो सब कुछ पकड़ लेगा। ध्यान दें कि तब से, आपकी वेब एपीआई अब स्थैतिक संसाधनों के रूप में डॉट्स के साथ आने वाली कॉल की व्याख्या नहीं करेगी! यदि आप अपने वेब एपीआई पर स्थिर संसाधनों की मेजबानी कर रहे हैं, तो इसकी सलाह नहीं दी जाती है!
  • सभी अनुरोधों को बिना शर्त के संभालने के लिए अपने Web.config में निम्न जोड़ें <system.webserver>:<modules runAllManagedModulesForAllRequests="true">

2. :मार्ग में

उपरोक्त परिवर्तन करने के बाद, डिफ़ॉल्ट रूप से, आपको निम्न त्रुटि मिलेगी:

संभावित रूप से खतरनाक Request.Path मान क्लाइंट (:) से पाया गया था।

आप अपने Web.config में पूर्वनिर्धारित अस्वीकृत / अमान्य वर्ण बदल सकते हैं। के तहत <system.web>, निम्नलिखित जोड़ें <httpRuntime requestPathInvalidCharacters="&lt;,&gt;,%,&amp;,*,\,?" />:। मैंने :अमान्य वर्णों की मानक सूची से निकाल दिया है ।

आसान / सुरक्षित समाधान

यद्यपि आपके प्रश्न का उत्तर नहीं है, लेकिन सुरक्षित और आसान समाधान अनुरोध को बदलना होगा ताकि यह सब आवश्यक न हो। इसे दो तरीकों से किया जा सकता है:

  1. दिनांक को क्वेरी स्ट्रिंग पैरामीटर के रूप में पास करें, जैसे ?date=2012-12-31T22:00:00.000Z
  2. .000हर रिक्वेस्ट से स्ट्रिप करें । आपको अभी भी अनुमति देने :की आवश्यकता होगी (cfr बिंदु 2)।

आपके "आसान समाधान" ने मूल रूप से मेरे लिए यह किया क्योंकि मुझे सेकंड की आवश्यकता नहीं थी।
नेवले

आप एक जीवन रक्षक हैं :)
Moeez

1
आपके "आसान समाधान" में, :एस की अनुमति देने के बजाय , मुझे लगता है कि आप बस के %3Aस्थान पर उपयोग कर सकते हैं :और यह ठीक होना चाहिए।
मेयर स्पिट्जर

20

अपने उत्पाद में वेब एपीआई नियंत्रक:

[RoutePrefix("api/product")]
public class ProductController : ApiController
{
    private readonly IProductRepository _repository;
    public ProductController(IProductRepository repository)
    {
        this._repository = repository;
    }

    [HttpGet, Route("orders")]
    public async Task<IHttpActionResult> GetProductPeriodOrders(string productCode, DateTime dateStart, DateTime dateEnd)
    {
        try
        {
            IList<Order> orders = await _repository.GetPeriodOrdersAsync(productCode, dateStart.ToUniversalTime(), dateEnd.ToUniversalTime());
            return Ok(orders);
        }
        catch(Exception ex)
        {
            return NotFound();
        }
    }
}

फ़िडलर में GetProductPeriodOrders विधि का परीक्षण करें - संगीतकार:

http://localhost:46017/api/product/orders?productCode=100&dateStart=2016-12-01T00:00:00&dateEnd=2016-12-31T23:59:59

दिनांक समय प्रारूप:

yyyy-MM-ddTHH:mm:ss

जावास्क्रिप्ट पास पैरामीटर क्षण का उपयोग करें। js

const dateStart = moment(startDate).format('YYYY-MM-DDTHH:mm:ss');
const dateEnd = moment(endDate).format('YYYY-MM-DDTHH:mm:ss');

18

मैं आपका दर्द महसूस करता हूं ... फिर भी एक और तारीख समय प्रारूप ... बस आपको क्या चाहिए!

वेब एपि 2 का उपयोग कर आप मापदंडों को निर्दिष्ट करने के लिए मार्ग विशेषताओं का उपयोग कर सकते हैं।

इसलिए अपनी कक्षा और अपनी पद्धति पर विशेषताओं के साथ आप इस utc प्रारूप का उपयोग करके एक REST URL को कोड कर सकते हैं जिससे आपको परेशानी हो रही है (स्पष्ट रूप से इसके ISO8601, संभवतः startDate.toISOString () का उपयोग करके)

[Route(@"daterange/{startDate:regex(^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$)}/{endDate:regex(^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$)}")]
    [HttpGet]
    public IEnumerable<MyRecordType> GetByDateRange(DateTime startDate, DateTime endDate)

.... लेकिन, हालांकि यह एक तारीख (आरंभ) के साथ काम करता है, किसी कारण से यह काम नहीं करता है जब एंडेडेट इस प्रारूप में होता है ... घंटों के लिए डीबग किया जाता है, केवल सुराग यह कहता है कि यह बृहदान्त्र की तरह नहीं है ":" (यहां तक ​​कि हालाँकि web.config के साथ सेट किया गया है:

<system.web>
    <compilation debug="true" targetFramework="4.5.1" />
    <httpRuntime targetFramework="4.5.1" requestPathInvalidCharacters="" />
</system.web>

तो, एक और तारीख प्रारूप बनाने की अनुमति देता है (आईएसओ तिथि प्रारूप के लिए पॉलीफ़िल से लिया गया है) और इसे जावास्क्रिप्ट तिथि में जोड़ें (संक्षिप्तता के लिए, केवल मिनट तक परिवर्तित करें):

if (!Date.prototype.toUTCDateTimeDigits) {
    (function () {

        function pad(number) {
            if (number < 10) {
                return '0' + number;
            }
            return number;
        }

        Date.prototype.toUTCDateTimeDigits = function () {
            return this.getUTCFullYear() +
              pad(this.getUTCMonth() + 1) +
              pad(this.getUTCDate()) +
              'T' +
              pad(this.getUTCHours()) +
              pad(this.getUTCMinutes()) +
              'Z';
        };

    }());
}

फिर जब आप वेब एपीआई 2 विधि को तारीखें भेजते हैं, तो आप उन्हें स्ट्रिंग से तारीख में परिवर्तित कर सकते हैं:

[RoutePrefix("api/myrecordtype")]
public class MyRecordTypeController : ApiController
{


    [Route(@"daterange/{startDateString}/{endDateString}")]
    [HttpGet]
    public IEnumerable<MyRecordType> GetByDateRange([FromUri]string startDateString, [FromUri]string endDateString)
    {
        var startDate = BuildDateTimeFromYAFormat(startDateString);
        var endDate = BuildDateTimeFromYAFormat(endDateString);
    ...
    }

    /// <summary>
    /// Convert a UTC Date String of format yyyyMMddThhmmZ into a Local Date
    /// </summary>
    /// <param name="dateString"></param>
    /// <returns></returns>
    private DateTime BuildDateTimeFromYAFormat(string dateString)
    {
        Regex r = new Regex(@"^\d{4}\d{2}\d{2}T\d{2}\d{2}Z$");
        if (!r.IsMatch(dateString))
        {
            throw new FormatException(
                string.Format("{0} is not the correct format. Should be yyyyMMddThhmmZ", dateString)); 
        }

        DateTime dt = DateTime.ParseExact(dateString, "yyyyMMddThhmmZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);

        return dt;
    }

इसलिए url होगा

http://domain/api/myrecordtype/daterange/20140302T0003Z/20140302T1603Z

हंसेलमैन कुछ संबंधित जानकारी यहां देता है:

http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx


WebAPI विधि में आप डेटालटाइम पैरामीटर डेटेबल के रूप में डेटटाइम कर सकते हैं (DateTime? StartDateString, DateTime? EndDateDtring)
फैन

इस toISOString के उल्लेख के लिए धन्यवाद - जिसने मुझे बचाया। मेरा RESTful WCF सेवा URI में दो तिथियों के साथ ठीक काम करता है, इसलिए आपको अपने जटिल दिनांक रूपांतरणों की आवश्यकता नहीं है। हो सकता है कि यह वेब एपीआई के साथ एक क्वर्क है, जो विन्यास सेटिंग के बावजूद कॉलन को पसंद नहीं कर रहा है ... हालांकि अजीब है।
नेविल

@Simon, endDateअगर उरल अनुरोध एक अनुगामी अग्रेषण स्लैश शामिल है काम करेगा। दुर्भाग्य से मुझे याद नहीं आ रहा है कि मैं इस जानकारी में कहाँ आया हूँ, और न ही मुझे इसके बारे में कोई रास्ता पता है।
पूर्वाह्न

24h घड़ी उपयोगकर्ता जो इसका उपयोग करना चाहते हैं, उन्हें तिथि प्रारूप में hh को HH में बदलना चाहिए।
स्नैट्स

यह सही जवाब है। स्टैकऑवरफ़्लो, रोकना डाउनलोड करने वाले ANSWERS!
मझौआ

8

Sk के उत्तर के समान विकल्प के रूप में, मैं Date.prototype.toISOString()क्वेरी स्ट्रिंग में प्रारूपित तारीख को पास करने में सक्षम हूं । यह मानक आईएसओ 8601 प्रारूप है, और यह मार्ग या कार्रवाई के किसी भी अतिरिक्त कॉन्फ़िगरेशन के बिना .Net वेब एपीआई नियंत्रकों द्वारा स्वीकार किया जाता है।

जैसे

var dateString = dateObject.toISOString(); // "2019-07-01T04:00:00.000Z"

1
क्या यह? क्या आप कोई उदाहरण प्रदान कर सकते हैं जहां यह काम करता है? मैंने एक ही वर्कअराउंड किया और यह काम नहीं करता है।
अनातोल

@anatol आपको क्या परिणाम मिलता है? प्रदान की गई कोड dateObjectएक प्रारंभिक उदाहरण है, पूर्व स्थिति के साथ जो एक प्रारंभिक Dateवस्तु है।
बॉन्डोलिन

यह शायद थोड़ा ऊपर मतदान किया जाना चाहिए। इसने UTC को ISO में बदलकर मेरी समस्या हल कर दी। साधारण
Regianni

1
@Regianni ने खुशी से मदद की :-)
बॉन्डोलिन

यह मेरे लिए stackoverflow.com/a/115034/1302730 का उपयोग करके आईएसओ प्रारूप में तारीख पाने के लिए काम करता है
BugLover

7

यह एक समाधान है और संभव समाधान के लिए एक मॉडल है। अपने क्लाइंट में मोमेंट्स.जेएस का उपयोग तारीखों को प्रारूपित करने के लिए करें, यूनिक्स समय में परिवर्तित करें।

 $scope.startDate.unix()

लंबे होने के लिए अपने रूट पैरामीटर सेट करें।

[Route("{startDate:long?}")]
public async Task<object[]> Get(long? startDate)
{
    DateTime? sDate = new DateTime();

        if (startDate != null)
        {
            sDate = new DateTime().FromUnixTime(startDate.Value); 
        }
        else
        {
            sDate = null;
        }
         ... your code here!
  }

यूनिक्स समय के लिए एक विस्तार विधि बनाएं। यूनिक्स डेटाइम विधि


4

यह एक दर्दनाक काम हुआ करता था, लेकिन अब हम toUTCString () का उपयोग कर सकते हैं:

उदाहरण:

[HttpPost]
public ActionResult Query(DateTime Start, DateTime End)

नीचे अजाक्स पोस्ट अनुरोध में डालें

data: {
    Start: new Date().toUTCString(),
    End: new Date().toUTCString()
},

3

तथ्य के रूप में, स्पष्ट रूप से मापदंडों को निर्दिष्ट करना? तिथि = 'फुलडलटाइम' एक आकर्षण की तरह काम करता है। तो यह अब के लिए एक समाधान होगा: कॉमा का उपयोग न करें, लेकिन पुराने जीईटी दृष्टिकोण का उपयोग करें।


0

चूंकि मेरे पास ISO-8859-1 ऑपरेटिंग सिस्टम एन्कोडिंग है, इसलिए दिनांक स्वरूप "dd.MM.yyyy HH: mm: sss" को मान्यता नहीं दी गई थी कि InvariantCulture स्ट्रिंग का उपयोग करने के लिए क्या काम किया गया था।

string url = "GetData?DagsPr=" + DagsProfs.ToString(CultureInfo.InvariantCulture)

0

आपके कोड को देखकर, मुझे लगता है कि आपको दिनांक समय ऑब्जेक्ट के 'समय' के बारे में चिंता नहीं है। यदि ऐसा है, तो आप दिनांक, माह और वर्ष को पूर्णांक मापदंडों के रूप में पास कर सकते हैं। कृपया निम्न कोड देखें। यह मेरी वर्तमान परियोजना का एक कार्यशील उदाहरण है।

फायदा है; यह विधि मुझे डेटटाइम प्रारूप मुद्दों और संस्कृति असंगतताओं से बचने में मदद करती है।

    /// <summary>
    /// Get Arrivals Report Seven Day Forecast
    /// </summary>
    /// <param name="day"></param>
    /// <param name="month"></param>
    /// <param name="year"></param>
    /// <returns></returns>
    [HttpGet("arrivalreportsevendayforecast/{day:int}/{month:int}/{year:int}")]
    public async Task<ActionResult<List<ArrivalsReportSevenDayForecastModel>>> GetArrivalsReportSevenDayForecast(int day, int month, int year)
    {
        DateTime selectedDate = new DateTime(year, month, day);
        IList<ArrivalsReportSevenDayForecastModel> arrivingStudents = await _applicationService.Value.GetArrivalsReportSevenDayForecast(selectedDate);
        return Ok(arrivingStudents);
    }

यदि आप सामने वाले को भी देखने के इच्छुक हैं, तो नीचे दिए गए कोड को पढ़ने के लिए स्वतंत्र महसूस करें। दुर्भाग्य से, कि कोणीय में लिखा गया है। इस तरह से मैं सामान्य रूप से डेट्यूल को कोणीय GET अनुरोधों में क्वेरी पैरामीटर के रूप में पास करता हूं।

public getArrivalsReportSevenDayForecast(selectedDate1 : Date): Observable<ArrivalsReportSevenDayForecastModel[]> {
const params = new HttpParams();
const day = selectedDate1.getDate();
const month = selectedDate1.getMonth() + 1
const year = selectedDate1.getFullYear();

const data = this.svcHttp.get<ArrivalsReportSevenDayForecastModel[]>(this.routePrefix +
  `/arrivalreportsevendayforecast/${day}/${month}/${year}`, { params: params }).pipe(
  map<ArrivalsReportSevenDayForecastModel[], ArrivalsReportSevenDayForecastModel[]>(arrivingList => {
    // do mapping here if needed       
    return arrivingList;
  }),
  catchError((err) => this.svcError.handleError(err)));

return data;
}

0

एक संभव उपाय टिक्स का उपयोग करना है:

सार्वजनिक लंबी टिक्स {मिलता है; }

फिर नियंत्रक विधि में:

सार्वजनिक डेटटाइम (लंबी टिक);

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.