ApiControllers सभी के लिए अच्छे हैं, लेकिन वे WSDL का निर्माण नहीं करते हैं और आप केवल प्रॉक्सिज्म प्राप्त और प्राप्त नहीं कर सकते हैं। हाँ, ApiControllers को यूनिट परीक्षणों द्वारा काफी अच्छी तरह से परखा जाता है। लेकिन इकाइयाँ परिवहन-स्तर की त्रुटियों को याद कर रही हैं और सामान्य तौर पर, अंत-टू-एंड स्क्रिप्ट के एक जोड़े के बिना किसी तरह असुविधाजनक है। आप निश्चित रूप से डाल सकते हैं, HttpClient ले सकते हैं और इस तरह से कुछ लिख सकते हैं:
HttpClient client = new HttpClient(); client.BaseAddress = new Uri("http://localhost:56851/"); // Add an Accept header for JSON format. client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = client.GetAsync("api/User").Result; if (response.IsSuccessStatusCode) { var users = response.Content.ReadAsAsync<IEnumerable<Users>>().Result; usergrid.ItemsSource = users; } else { MessageBox.Show("Error Code" + response.StatusCode + " : Message - " + response.ReasonPhrase); }
लेकिन नियंत्रकों के विवरण में आने के लिए हर बार यह कैसे उबाऊ हो जाता है, प्रकारों की जांच करें, संक्षेप में, मैं यह पसंद करना चाहता हूं:
var resp = GetResponse<SomeController>(c => gc.SomeAction(new Dto(){val = "123"}))
जैसा कि यह निकला, यह अच्छी तरह
से अभिव्यक्ति पेड़ों के
लिए कुछ सड़क जादू लागू करके महसूस किया जा सकता है
एपीआई जानकारी प्राप्त करना
पहले हमें यह जानना होगा कि एपीआई क्या है, इसके लिए हम मार्गों का नक्शा तैयार करेंगे
[SetUp] public void SetUp() { _cfg = new HttpConfiguration(); _cfg.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); }
रिमोट विधि कॉल
ApiDeslass अब जानता है कि नियंत्रकों को कहां देखना है और कृपया इसे मेटानफॉर्मेशन प्रदान करेगा। WebApi के पास एकल पद्धति को कॉल करने के कई विकल्प हो सकते हैं: मैं कभी भी एक एपीआई विधि के लिए दो Http विधियों का उपयोग नहीं करता, इसलिए यह मामला मुझे परेशान नहीं करता है। एक स्पष्ट विवेक के साथ, हम पहली उपयुक्त विधि लेते हैं
protected HttpResponseMessage GetResponse<T>(Expression<Action<T>> expression) where T : ApiController { var baseAddress = System.Configuration.ConfigurationManager.AppSettings["BaseAddress"]; var convert = (MethodCallExpression)expression.Body; var name = convert.Method.Name; var pars = convert.Method.GetParameters().ToArray(); var desc = _cfg.Services.GetApiExplorer().ApiDescriptions.First( d => d.ActionDescriptor.ControllerDescriptor.ControllerType == typeof(T) && d.ActionDescriptor.ActionName == name);
सं मान २। JSON के अलावा, मुझे किसी भी चीज़ में दिलचस्पी नहीं है। प्राप्त करने के तरीकों और मापदंडों में प्रधानता के साथ, हम फॉर्म के नाम को प्रतिस्थापित करते हैं paramName = {paramName} को paramName = अभिव्यक्ति से मूल्य, जो हमने पास किया था।
using (var client = new HttpClient { BaseAddress = new Uri(baseAddress) }) { client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); var relPath = desc.RelativePath; var index = 0; if (relPath.Contains("?")) { foreach (var p in pars) { relPath = relPath.Replace( string.Format("{{{0}}}", pars.Name), InvokeExpression(convert.Arguments[index++], p.ParameterType).Return(o => o.ToString(), string.Empty)); } }
InvokeExpression
किसी भी अभिव्यक्ति के मूल्य को प्राप्त करने का सबसे आसान तरीका यह है कि इसे लंबोदर में संकलित किया जाए, जो मैंने किया। सच कहूँ तो, हम नियंत्रक प्रकार से संकलन समय पर वापसी प्रकार जानते हैं। लेकिन इस मामले में आपको शून्य पर लौटने वाले तरीकों के लिए एक अलग मामला बनाना होगा। इस मामले में, आपको फंक <टी, ट्रेज़ल्ट> के बजाय एक्शन का उपयोग करना होगा। इस तरह के कोड को समझने के लिए पहले से ही काफी जटिल है। मैं प्रदर्शन का पीछा नहीं करता हूं - नेटवर्क की लागत उन सभी नैनोसेकंडों को इकट्ठा करेगी जो संकलन पर सहेजे जाएंगे।
private static object InvokeExpression(Expression e, Type returnType) { return Expression.Lambda( typeof (Func<>).MakeGenericType(returnType), e).Compile().DynamicInvoke(); }
नतीजा मिल रहा है
सबसे सरल बात यह है कि परिणाम प्राप्त करें और विधि को कॉल करें। पोस्ट विधियों के लिए, हम मानते हैं कि हमेशा एक मूल आवरण वस्तु होती है। हम परिणाम वापस करते हैं या एक त्रुटि के साथ आते हैं।
var uri = new Uri(new Uri(baseAddress), relPath); var resp = desc.HttpMethod.Method == HttpMethod.Post.ToString() ? client.PostAsJsonAsync(uri.ToString(), InvokeExpression(convert.Arguments.Single(), desc.ParameterDescriptions.Single().ParameterDescriptor.ParameterType)).Result : client.GetAsync(uri).Result; if (resp.StatusCode == HttpStatusCode.InternalServerError) { using (var sr = new StreamReader(resp.Content.ReadAsStreamAsync().Result)) { throw new InvalidOperationException(sr.ReadToEnd()); } } return resp;
अंत में
परिणाम यह विधि है
protected HttpResponseMessage GetResponse<T>(Expression<Action<T>> expression) where T : ApiController { var baseAddress = System.Configuration.ConfigurationManager.AppSettings["BaseAddress"]; var convert = (MethodCallExpression)expression.Body; var name = convert.Method.Name; var pars = convert.Method.GetParameters().ToArray(); var desc = _cfg.Services.GetApiExplorer().ApiDescriptions.First( d => d.ActionDescriptor.ControllerDescriptor.ControllerType == typeof(T) && d.ActionDescriptor.ActionName == name); using (var client = new HttpClient { BaseAddress = new Uri(baseAddress) }) { client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); var relPath = desc.RelativePath; var index = 0; if (relPath.Contains("?")) foreach (var p in pars) { relPath = relPath.Replace( string.Format("{{{0}}}", p.Name), InvokeExpression(convert.Arguments[index++], p.ParameterType).Return(o => o.ToString(), string.Empty)); } var uri = new Uri(new Uri(baseAddress), relPath); var resp = desc.HttpMethod.Method == HttpMethod.Post.ToString() ? client.PostAsJsonAsync(uri.ToString(), InvokeExpression(convert.Arguments.Single(), desc.ParameterDescriptions.Single().ParameterDescriptor.ParameterType)).Result : client.GetAsync(uri).Result; if (resp.StatusCode == HttpStatusCode.InternalServerError) { using (var sr = new StreamReader(resp.Content.ReadAsStreamAsync().Result)) { throw new InvalidOperationException(sr.ReadToEnd()); } } return resp; } }
इस कोड में बहुत सी चीजें सही नहीं हैं, लेकिन यह अपने लक्ष्य को पूरा करेगी, अब मैं इस तरह के परीक्षण लिख सकता हूं:
[Test] public void UserController_TokenValid_WrongTokenReturnFalse() { var resp = GetResponse<UserController>(gc => gc.TokenValid("123")); Assert.AreEqual(false, resp.Content.ReadAsAsync<bool>().Result); }
या अधिक जटिल, उदाहरण के लिए, ये:
var obj = new RoundResultDtoIn() { LevelId = 3, RoomName = "123", RoundTime = 50, StartDateTime = DateTime.Now }; GetResponse<GameController>(gc => gc.SaveResults(obj));