рдХреНрд▓рд╛рд╕рд┐рдХ ASP.NET рдореЗрдВ рдПрдХ рдкреНрд░рддрд┐рд╖реНрдард┐рдд рд╕реЗрд╡рд╛ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛

рд▓реЗрдЦ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рдХреИрд╕реЗ рдПрдХ рдореМрдЬреВрджрд╛ рдХреНрд▓рд╛рд╕рд┐рдХ ASP.NET рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдВ рдПрдХ RESTful рдПрдкреАрдЖрдИ рдХреЛ рдЬрд▓реНрджреА рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПред
MVC рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреА рдХреНрд╖рдорддрд╛рдУрдВ рдХрд╛ рдЕрдзрд┐рдХрддрдо рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░реЗрдВред

рд╣рдо рдХрд┐рди рдЙрдкрдХрд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ

1. System.Web.Routingред MyTite.ru/rest/client/0 рдЬреИрд╕реЗ рд▓рд┐рдВрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд░реВрдЯрдЯреЗрдмрд▓ рдФрд░ IRouteHandler
2. System.Web.Mvcред DefaultModelBinder рдореЙрдбрд▓ рдХреЗ рдЕрдиреБрд░реЛрдз рд╕реЗ рдбреЗрдЯрд╛ рд▓рд┐рдЦрдиреЗ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП
3. рдкреНрд░рдгрд╛рд▓реАред IHttpHandler рдХреЛ CRUD рд╕рдВрдЪрд╛рд▓рди рдореЗрдВ рд╕реЗ рдПрдХ рдореЗрдВ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП

рдХрд╛рд░реНрдп рд╕рд┐рджреНрдзрд╛рдВрдд

рд░реВрдЯрдЯреЗрдмрд▓ рдореЗрдВ рд╣рдо рд░реВрдЯ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рдЬреЛ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЗ рдЕрдиреБрд╕рд╛рд░, рдЙрд╕ рдЕрдиреБрд░реЛрдз рдХреЛ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рд╣рдореЗрдВ HttpHandler рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рд╣рдо рджреЛ рд░реВрдЯ рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд░рддреЗ рд╣реИрдВ - рд╕реАрдЖрд░рдпреВрдбреА рдСрдкрд░реЗрд╢рдВрд╕ рдХреЗ рд▓рд┐рдП рдФрд░ рдкреИрд░рд╛рдореАрдЯрд░реНрд╕ рд╕рд░реНрдЪ рдСрдкрд░реЗрд╢рдВрд╕ рдХреЗ рд▓рд┐рдПред
HttpHandler рдЕрдиреБрд░реЛрдз рд╡рд┐рдзрд┐ рдФрд░ рдкрд╛рд░рд┐рдд рдорд╛рдкрджрдВрдбреЛрдВ рджреНрд╡рд╛рд░рд╛ рд╡рд╛рдВрдЫрд┐рдд рд╕рдВрдЪрд╛рд▓рди рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИред
рдпрджрд┐ рдпрд╣ рдПрдХ рдЕрдиреБрд░реЛрдз рд╣реИ рдФрд░ рдХреНрд╡реЗрд░реА рдкреИрд░рд╛рдореАрдЯрд░ рдореМрдЬреВрдж рд╣реИ, рддреЛ рдкреИрд░рд╛рдореАрдЯрд░ рджреНрд╡рд╛рд░рд╛ рдПрдХ рдЦреЛрдЬ рдСрдкрд░реЗрд╢рди рдЪреБрдирд╛ рдЬрд╛рддрд╛ рд╣реИред
рдпрджрд┐ рдпрд╣ рдПрдХ рд▓реЗрдЦрди рдСрдкрд░реЗрд╢рди (рдХреНрд░рд┐рдПрдЯ, рдЕрдкрдбреЗрдЯ, рдбрд┐рд▓реАрдЯ) рд╣реИ, рддреЛ DefaultModelBinder рд╡рдВрд╢рдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╡рд╛рдВрдЫрд┐рдд рдореЙрдбрд▓ рдмрдирд╛рдиреЗ рдпрд╛ рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЕрдиреБрд░реЛрдз рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдбреЗрдЯрд╛ рдЙрд╕ рдкрд░ рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИред
рд░реАрдб рдСрдкрд░реЗрд╢рди рдХреЗ рджреМрд░рд╛рди, рдпрджрд┐ рдЖрдИрдбреА рдкреИрд░рд╛рдореАрдЯрд░ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдПрдХ рдореЙрдбрд▓ рдХрд╛ рдЪрдпрди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдпрджрд┐ рдЖрдИрдбреА рдкрд╛рд╕ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ, рддреЛ рдореЙрдбрд▓ рдХрд╛ рдкреВрд░рд╛ рд╕рдВрдЧреНрд░рд╣ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рддрд╛ рд╣реИред
рдореЙрдбрд▓ рдХреЛ JSON рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдВрддрд┐рдо рдЪрд░рдг рд╣реИред

рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ 30 рд╕реЗрдХрдВрдб рдХреЗ рд▓рд┐рдП рдХреИрд╢рд┐рдВрдЧ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддреА рд╣реИред
рдореИрдВрдиреЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд┐рдпрд╛ рддрд╛рдХрд┐ рдХреЛрдб рдХреЛ рдЕрд╡реНрдпрд╡рд╕реНрдерд┐рдд рди рдХрд┐рдпрд╛ рдЬрд╛рдПред

рдХрд┐рд╕реА рд╕рдорд╛рдзрд╛рди рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддреЗ рд╕рдордп, рджреЛ рдХрдард┐рдирд╛рдЗрдпрд╛рдБ рдЙрддреНрдкрдиреНрди рд╣реЛ рд╕рдХрддреА рд╣реИрдВ:
1. 404 рддреНрд░реБрдЯрд┐ - IIS рдореЗрдВ рдлрд╝рд╛рдЗрд▓ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреА рдЬрд╛рдВрдЪ рдХреЛ рдЕрдХреНрд╖рдо рдХрд░рдХреЗ рдЗрд▓рд╛рдЬ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
( рдпрд╣рд╛рдВ рджреЗрдЦреЗрдВ рдпрд╛ рдиреАрдЪреЗ web.config рд╕реЗрдЯрд┐рдВрдЧреНрд╕)
2. рд╕рддреНрд░ рдХреА рд╡рд╕реНрддреБ рдЕрдиреБрдкрд╕реНрдерд┐рдд рд╣реИ - рдЗрд╕рдХрд╛ рдЙрдкрдЪрд╛рд░ рд╕рддреНрд░ рдореЙрдбреНрдпреВрд▓ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрдВрдЬреАрдХреГрдд рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
( рдпрд╣рд╛рдВ рджреЗрдЦреЗрдВ рдпрд╛ рдиреАрдЪреЗ web.config рд╕реЗрдЯрд┐рдВрдЧреНрд╕)

рдЖрд╡реЗрджрди рд╕реНрд░реЛрдд рдпрд╣рд╛рдВ рд╕реЗ рдбрд╛рдЙрдирд▓реЛрдб рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ

рдЧреНрд░рд╛рд╣рдХ рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП рд╕реЗрд╡рд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЙрджрд╛рд╣рд░рдг

рдХреНрд▓рд╛рд╕ ClientRestHttpHandler
public class ClientRestHttpHandler : RestHttpHandler<Client, ClientModelBinder> { protected override IEnumerable<Client> GetAll() { return ClientService.GetAll(); } protected override Client GetBy(int id) { return ClientService.GetById(id); } protected override IEnumerable<Client> GetBy(NameValueCollection query) { var result = ClientService.GetAll(); var contains = query["contains"]; if (contains != null) { result = from item in result where item.FirstName.Contains(contains) || item.LastName.Contains(contains) select item; } return result; } protected override void Create(Client entity) { ClientService.Create(entity); } protected override void Update(Client entity) { ClientService.Update(entity); } protected override void Delete(Client entity) { ClientService.Delete(entity); } protected override object ToJson(Client entity) { return new { entity.Id, entity.FirstName, entity.LastName }; } } 


рдХреНрд▓рд╛рд╕ ClientModelBinder
 public class ClientModelBinder : DefaultModelBinder { protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, System.Type modelType) { var value = bindingContext.ValueProvider.GetValue("id"); if (value == null) return ClientService.New(); var result = (int)value.ConvertTo(typeof(int)); return ClientService.GetById(result); } } 


Global.asax рдореЗрдВ рдирд╛рдо
  void Application_Start(object sender, EventArgs e) { RestRouteHandler<ClientRestHttpHandler>.Register("client", "clients"); } 


рд╡реЗрдм рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛
 <configuration> <system.webServer> <modules runAllManagedModulesForAllRequests="true"> <!-- fix for empty session on RESTful requests. see http://stackoverflow.com/questions/218057/httpcontext-current-session-is-null-when-routing-requests --> <remove name="Session" /> <add name="Session" type="System.Web.SessionState.SessionStateModule"/> </modules> <handlers> <add name="WildCard" path="*" verb="*" resourceType="Unspecified" /> </handlers> </system.webServer> </configuration> 


рдпрд╣реА рд╣реИ, рдХреНрд▓рд╛рдЗрдВрдЯ рдореЙрдбрд▓ рд╣рдорд╛рд░реА рд╡реЗрдмрд╕рд╛рдЗрдЯ рд╕реЗ REST API рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЙрдкрд▓рдмреНрдз рд╣реИред

рдмреЗрд╕ рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рд╕реНрд░реЛрдд рд░реЗрд╕реНрдЯрд╣реЗрдЯрдлреИрдВрдбрд▓рд░ рдФрд░ рд░реЗрд╕реНрдЯреЗрд░рдЯрд╣реИрдВрдбрд▓рд░

 public abstract class RestHttpHandler : IHttpHandler, IReadOnlySessionState { public const string ParamKeyId = "id"; public const string ParamKeyQuery = "query"; /// <summary> /// RouteData property gives an access to request data provided by the router /// It has a setter to simplify instantiation from the RestRouteHandler class /// </summary> public RouteData RouteData { get; set; } protected bool HasId { get { return this.RouteData.Values[ParamKeyId] != null; } } protected bool HasQuery { get { return this.RouteData.Values[ParamKeyQuery] != null; } } protected int ParseId() { return int.Parse(this.RouteData.Values[ParamKeyId].ToString()); } protected NameValueCollection ParseQuery() { var regex = new Regex("(?<key>[a-zA-Z\\-]+)($|/)(?<value>[^/]+)?"); var matches = regex.Matches(this.RouteData.Values[ParamKeyQuery].ToString()); var result = new NameValueCollection(); foreach (Match match in matches) { result.Add(match.Groups["key"].Value, match.Groups["value"].Value); } return result; } public bool IsReusable { get { return false; } } public abstract void ProcessRequest(HttpContext context); } 


 public abstract class RestHttpHandler<T, TBinder> : RestHttpHandler where T : class where TBinder : DefaultModelBinder, new() { /// <summary> /// ProcessRequest actually does request mapping to one of CRUD actions /// </summary> public override void ProcessRequest(HttpContext context) { var @params = new NameValueCollection { context.Request.Form, context.Request.QueryString }; foreach (var value in this.RouteData.Values) { @params.Add(value.Key, value.Value.ToString()); } RenderHeader(context); if (context.Request.HttpMethod == "GET") { if (this.HasQuery) { @params.Add(this.ParseQuery()); this.Render(context, this.GetBy(@params)); } else { if (this.HasId) { this.Render(context, this.GetBy(this.ParseId())); } else { this.Render(context, this.GetAll()); } } } else { var entity = BindModel(@params); switch (context.Request.HttpMethod) { case "POST": this.Create(entity); break; case "PUT": this.Update(entity); break; case "DELETE": this.Delete(entity); break; default: throw new NotSupportedException(); } this.Render(context, entity); } } protected abstract T GetBy(int id); protected abstract IEnumerable<T> GetBy(NameValueCollection query); protected abstract IEnumerable<T> GetAll(); protected abstract void Create(T entity); protected abstract void Update(T entity); protected abstract void Delete(T entity); protected abstract object ToJson(T entity); private object ToJson(IEnumerable<T> entities) { return ( from entity in entities select this.ToJson(entity)).ToArray(); } private static T BindModel(NameValueCollection @params) { return new TBinder().BindModel( new ControllerContext(), new ModelBindingContext { ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(T)), ValueProvider = new NameValueCollectionValueProvider( @params, CultureInfo.InvariantCulture ) } ) as T; } private static void RenderHeader(HttpContext context) { context.Response.ClearHeaders(); context.Response.ClearContent(); context.Response.ContentType = "application/json"; context.Response.ContentEncoding = Encoding.UTF8; var cachePolicy = context.Response.Cache; cachePolicy.SetCacheability(HttpCacheability.Public); cachePolicy.SetMaxAge(TimeSpan.FromSeconds(30.0)); } private void Render(HttpContext context, IEnumerable<T> entities) { Render(context, RuntimeHelpers.GetObjectValue(this.ToJson(entities))); } private void Render(HttpContext context, T entity) { Render(context, RuntimeHelpers.GetObjectValue(this.ToJson(entity))); } private static void Render(HttpContext context, object result) { context.Response.Write( new JavaScriptSerializer().Serialize( RuntimeHelpers.GetObjectValue(result) ) ); } } 


 public class RestRouteHandler<T> : IRouteHandler where T : RestHttpHandler, new() { IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) { return new T() { RouteData = requestContext.RouteData }; } public static void Register(string name, string pluralName) { RouteTable.Routes.Add( name, new Route( string.Format( "rest/{0}/{{{1}}}", name, RestHttpHandler.ParamKeyId ), new RestRouteHandler<T>() ) { Defaults = new RouteValueDictionary { { RestHttpHandler.ParamKeyId, null } }, Constraints = new RouteValueDictionary { { RestHttpHandler.ParamKeyId, "\\d*" } } } ); RouteTable.Routes.Add( pluralName, new Route( string.Format( "rest/{0}/{{*{1}}}", pluralName, RestHttpHandler.ParamKeyQuery ), new RestRouteHandler<T>()) { Defaults = new RouteValueDictionary { { RestHttpHandler.ParamKeyQuery, "" } } } ); } } 

рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдореЗрд░рд╛ рдЕрдиреБрднрд╡ рдЖрдкрдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛрдЧрд╛ред

Source: https://habr.com/ru/post/In127811/


All Articles