generic相关知识
-
Generic-Host 快速使用指南.NETCORE 中的 Generic Host本文以自己在工作中学习和使用.net core generic-host 作一个总结。前言在创建的ASPNETCORE项目中,我们可以在Main()中看见,我们通过IWebHostBuild创建了一个IWebHost,而微软提供了WebHost.CreateDefaultBuilder(args)来帮助我们更轻松得创建WebHost。常常我们的需求不需要创建Web项目,比如后台任务,那么我们如何像使用AspNetCore一样创建控制台项目。如何在控制台程序中创建主机通过dotnet new console 创建一个控制台项目通过Nuget添加以下包Microsoft.Extensions.Hosting首先,我们看下IHostBuilder接口里的方法public interface IHostBuilder { IHost Build(); &
-
利用Topshelf把.NET Core Generic Host管理的应用程序部署为Windows服务1|0背景2019第一篇文章。此文源于前公司在迁移项目到.NET Core的过程中,希望使用Generic Host来管理定时任务程序时,没法部署到Windows服务的问题,而且官方也没给出解决方案。官方文档只提供了一个《在 Windows 服务中托管 ASP.NET Core》的方案,可以使用Microsoft.AspNetCore.Hosting.WindowsServices类库来把Web应用部署为Windows服务。但是ASP.NET Core虽然是控制台程序,但是它本身是使用了含有HTTP管道的Web Host来负责应用程序的生命周期管理,用它来作为定时任务的话,会有很多不必要的工作负载,例如占用端口、增加了很多依赖等等。官方意识到这个问题之后,在.NET Core 2.1版本新增了Generic Host通用主机,剥离了原来WebHost的Http管道相关的API,源码中可以发现Web Host已经基于Generic Host实现。它才是作为纯粹定时任务程序的最佳拍档。但是由于Generic H
-
Asp.net Core 2.1新功能Generic Host(通用主机)深度学习什么是Generic Host ? 这是在Asp.Net Core 2.1加入了一种新的Host,现在2.1版本的Asp.Net Core中,有了两种可用的Host。Web Host –适用于托管Web程序的Host,就是我们所熟悉的在Asp.Net Core应用程序的Mai函数中用CreateWebHostBuilder创建出来的常用的WebHost。Generic Host (ASP.NET Core 2.1版本才有) – 适用于托管非 Web 应用(例如,运行后台任务的应用)。 在未来的版本中,通用主机将适用于托管任何类型的应用,包括 Web 应用。 通用主机最终将取代 Web 主机,这大概也是这种类型的主机叫做通用主机的原因,在本博客中,我们将结合源码,讨论通用主机的工作原理。为什么要用通用主机?通用主机,让我可以用编写Asp.Net Core的思想(例如控制反转、依赖注入、IOC容器)来简化控制台应用程序的创建(个人见解),主机负责程序的启动和生存周期的管理,这对于不处理HTTP请求的应
-
用Generic Handler(ashx)去显示非二进制的图片一般情况,显示非二进制的图片(存放在磁盘上的图片文件),直接用图片控件轻易实现。<img alt="" src="xxx.jpg" /><asp:Image ID="Image1" runat="server" ImageUrl="xxx.jpg" /> 由于程序要求,需要把图片文件转为数据流(二进制),再进行显示。因此想起使用Generic Handler(ashx)来处理。你可以参考下面代码:View Code <%@ WebHandler Language="C#" Class="ViewImage" %>using System;using System.Data;using S
generic相关课程
generic相关教程
- 1. 慕课解释 泛型在传统的面向对象语言中极为常见,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。通俗来讲:泛型是指在定义函数、接口或者类时,未指定其参数类型,只有在运行时传入才能确定。那么此时的参数类型就是一个变量,通常用大写字母 T 来表示,当然你也可以使用其他字符,如:U、K等。语法:在函数名、接口名或者类名添加后缀 <T>:function generic<T>() {}interface Generic<T> {}class Generic<T> {}
- 2. ListView 类视图深入分析 首先在 VScode 中整体看看 ListView 的源代码,其源码路径为: djnago/views/generic/list.py。来看看ListView 类的整体继承关系:在红框中出现的对象我们是在 TemplateView 中已经遇到过了。这里可以看到 ListView 继承的比 TemplateView 要多且复杂。我们来一个个分析这些基础的类。
- TypeScript 泛型(Generic) 本节开始介绍 TypeScript 一些进阶知识点,第一个要介绍的泛型是 TypeScript 中非常重要的一个概念,它是一种用以增强函数、类和接口能力的非常可靠的手段。使用泛型,我们可以轻松地将那些输入重复的代码,构建为可复用的组件,这给予了开发者创造灵活、可重用代码的能力。
- 2.3 TemplateView 类 介绍完上面那些基础的类以及 Mixin 后,终于可以看 TemplateView 的代码了,我们发现它其实就是 View 类中混入了 ContextMixin 和 TemplateResponseMixin,此外还多了一个 get 函数,对应着 get 请求。# 源码路径 django/views/generic/base.pyclass TemplateView(TemplateResponseMixin, ContextMixin, View): """ Render a template. Pass keyword arguments from the URLconf to the context. """ def get(self, request, *args, **kwargs): context = self.get_context_data(**kwargs) return self.render_to_response(context)就是这个 get 请求方法让我们前面第一个实验中,只需要写对应的模板文件名,另外传递 extra_context 就可以渲染模板并返回。注意,这个 extra_context 属性是继承自 ContextMixin 对象,它的赋值过程是走的 View 类。现在可以通过代码分析一下这个复制过程,加深印象。首先看 as_view() 函数传参部分:context_data = {'content':'正文1', 'spyinx':{'age': 29}}urlpatterns = [ path('test_template_view/', views.TestTemplateView.as_view(extra_context=context_data), name='test_template_View')]as_view() 方法的源码如下。传进来的参数在 initkwargs 中,最后在 View 类中使用该字典参数初始化实例。# 源码位置: django/views/generic/base.py @classonlymethod def as_view(cls, **initkwargs): # ... def view(request, *args, **kwargs): self = cls(**initkwargs) # ... # ... return view最后来看 View 的初始化函数。可以看到这些初始化的参数会作为类的属性进赋值,使用的是 setattr() 方法,这样我们在 as_view() 方法中传递的 extra_context 参数就被成功赋值到 extra_context 属性上了。class View: """ Intentionally simple parent class for all views. Only implements dispatch-by-method and simple sanity checking. """ # ... def __init__(self, **kwargs): """ Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things. """ # Go through keyword arguments, and either save their values to our # instance, or raise an error. for key, value in kwargs.items(): setattr(self, key, value)其实通过了解这些源代码后,我们能很好得理解前面使用 TemplateView 类做的一些测试结果。目前来看,我们接触到的这部分源代码还是比较简单易懂的,官方网站对 Django 中出现的许多常用类都做了详细的介绍,我们只需要不停的学习源代码、参考官方的文档、坚持不懈,一定能达到精通 Django 的目的。
- 2.2 ContextMixin 和 TemplateResponseMixin 接下来,我们查看下 Django 提供的两个 mixin:ContextMixin 和 TemplateResponseMixin。其内容比较简单,源码如下:# 源码位置:django/views/generic/base.pyclass ContextMixin: """ A default context mixin that passes the keyword arguments received by get_context_data() as the template context. """ extra_context = None def get_context_data(self, **kwargs): kwargs.setdefault('view', self) if self.extra_context is not None: kwargs.update(self.extra_context) return kwargs class TemplateResponseMixin: """A mixin that can be used to render a template.""" template_name = None template_engine = None response_class = TemplateResponse content_type = None def render_to_response(self, context, **response_kwargs): """ Return a response, using the `response_class` for this view, with a template rendered with the given context. Pass response_kwargs to the constructor of the response class. """ response_kwargs.setdefault('content_type', self.content_type) return self.response_class( request=self.request, template=self.get_template_names(), context=context, using=self.template_engine, **response_kwargs ) def get_template_names(self): """ Return a list of template names to be used for the request. Must return a list. May not be called if render_to_response() is overridden. """ if self.template_name is None: raise ImproperlyConfigured( "TemplateResponseMixin requires either a definition of " "'template_name' or an implementation of 'get_template_names()'") else: return [self.template_name]ContextMixin 比较简单,只提供了一个属性 extra_context 和一个方法 get_context_data(),它主要的功能是根据额外提供的参数,组成新的上下文字典,调用 get_context_data() 方法即可实现。TemplateResponseMixin 是用来渲染模板的,它的属性与方法如下:属性:template_name:模板文件名;template_engine: 模板引擎;response_class: 返回的 Response,默认是 TemplateResponse;content_type:返回客户端的数据类型。方法:render_to_response():默认直接调用 TemplateResponse(),完成模板渲染后返回响应给客户端;get_template_names():获取模板名称,返回列表的形式;如果没有设置 template_name 属性值,则会报错。因此对于继承该 mixin 对象的子类,必须要设置 template_name 属性值。Mixin 的特点就是功能简单,它们可以混合加到其他类中,那么其他类就具备这些 Mixin 的功能,组合得到一个更高级的类。同样我们在前一小节实验的基础上改造下 views.py 中的内容,如下:class TestView(TemplateResponseMixin, View): template_name = 'test.html' def get(self, request, *args, **kwargs): return self.render_to_response(context={'content': '正文1', 'spyinx': {'age': 29}})这里我们额外继承 TemplateResponseMixin 类。首先需要添加 template_name 属性,指定要渲染的模板文件,然后调用从 TemplateResponseMixin 中继承过来的 render_to_response() 方法并返回。从源码角度来看,这个视图实现的功能和上一个小节中直接返回 TemplateResponse 实例是一样的。# 启动 first_django_app 工程...# 打开xshell另一个窗口,发送http请求[root@server first_django_app]# curl http://127.0.0.1:8888/hello/test-cbv/<p>正文1</p><div>29</div>
- 2. 深入理解 Django 类视图 这里在介绍完类视图的基本使用后,我们来深入学习下 Django 的源代码,看看 Django 是如何将对应的 HTTP 请求映射到对应的函数上。这里我们使用的是 Django 2.2.10 的源代码进行说明。我们使用 VSCode 打开 Django 源码,定位到 django/views/generic 目录下,这里是和视图相关的源代码。首先看 __init__.py 文件,内容非常少,主要是将该目录下的常用视图类导入到这里,简化开发者导入这些常用的类。其中最重要的当属 base.py 文件中定义的 view 类,它是其他所有视图类的基类。# base.py中常用的三个view类from django.views.generic.base import RedirectView, TemplateView, View# dates.py中定义了许多和时间相关的视图类from django.views.generic.dates import ( ArchiveIndexView, DateDetailView, DayArchiveView, MonthArchiveView, TodayArchiveView, WeekArchiveView, YearArchiveView,)# 导入DetailView类from django.views.generic.detail import DetailView# 导入增删改相关的视图类from django.views.generic.edit import ( CreateView, DeleteView, FormView, UpdateView,)# 导入list.py中定义的显示列表的视图类from django.views.generic.list import ListView__all__ = [ 'View', 'TemplateView', 'RedirectView', 'ArchiveIndexView', 'YearArchiveView', 'MonthArchiveView', 'WeekArchiveView', 'DayArchiveView', 'TodayArchiveView', 'DateDetailView', 'DetailView', 'FormView', 'CreateView', 'UpdateView', 'DeleteView', 'ListView', 'GenericViewError',]# 定义一个通用的视图异常类class GenericViewError(Exception): """A problem in a generic view.""" pass接下来,我们查看 base.py 文件,重点分析模块中定义的 View 类:# 源码路径 django/views/generic/base.py# 忽略导入# ...class View: http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] def __init__(self, **kwargs): # 忽略 # ... @classonlymethod def as_view(cls, **initkwargs): """Main entry point for a request-response process.""" for key in initkwargs: if key in cls.http_method_names: raise TypeError("You tried to pass in the %s method name as a " "keyword argument to %s(). Don't do that." % (key, cls.__name__)) if not hasattr(cls, key): raise TypeError("%s() received an invalid keyword %r. as_view " "only accepts arguments that are already " "attributes of the class." % (cls.__name__, key)) def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.setup(request, *args, **kwargs) if not hasattr(self, 'request'): raise AttributeError( "%s instance has no 'request' attribute. Did you override " "setup() and forget to call super()?" % cls.__name__ ) return self.dispatch(request, *args, **kwargs) view.view_class = cls view.view_initkwargs = initkwargs # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) return view # ... def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs) def http_method_not_allowed(self, request, *args, **kwargs): logger.warning( 'Method Not Allowed (%s): %s', request.method, request.path, extra={'status_code': 405, 'request': request} ) return HttpResponseNotAllowed(self._allowed_methods()) # 忽略其他函数 # ...# ...我们来仔细分析 view 类中的这部分代码。view 类首先定义了一个属性 http_method_names,表示其支持的 HTTP 请求方法。接下来最重要的是 as_view() 方法和 dispatch() 方法。在上面使用视图类的示例中,我们定义的 URLConf 如下:# first_django_app/hello_app/urls.pyfrom . import viewsurlpatterns = [ # 类视图 url(r'test-cbv/', views.TestView.as_view(), name='test-cbv'),]这里结合源码可以看到,views.TestView.as_view() 返回的结果同样是一个函数:view(),它的定义和前面的视图函数一样。as_view() 函数可以接收一些参数,函数调用会先对接收的参数进行检查:for key in initkwargs: if key in cls.http_method_names: raise TypeError("You tried to pass in the %s method name as a " "keyword argument to %s(). Don't do that." % (key, cls.__name__)) if not hasattr(cls, key): raise TypeError("%s() received an invalid keyword %r. as_view " "only accepts arguments that are already " "attributes of the class." % (cls.__name__, key))上面的代码会对 as_view() 函数传递的参数做两方面检查:首先确保传入的参数不能有 get、post 这样的 key 值,否则会覆盖 view 类中的对应方法,这样对应的请求就无法正确找到函数进行处理。覆盖的代码逻辑如下:class View: # ... def __init__(self, **kwargs): # 这里会将所有的传入的参数通过setattr()方法给属性类赋值 for key, value in kwargs.items(): setattr(self, key, value) # ... @classonlymethod def as_view(cls, **initkwargs): # ... def view(request, *args, **kwargs): # 调用视图函数时,会将这些参数传给View类来实例化 self = cls(**initkwargs) # ... # ... # ...此外,不可以传递类中不存在的属性值。假设我们将上面的 URLConf 进行略微修改,如下:from . import viewsurlpatterns = [ # 类视图 url(r'test-cbv/', views.TestView.as_view(no_key='hello'), name='test-cbv'),]启动后,可以发现 Django 报错如下,这正是由本处代码抛出的异常。接下来看下 update_wrapper() 方法,这个只是 python 内置模块中的一个方法,只是比较少用,所以会让很多人感到陌生。先看它的作用:update_wrapper() 这个函数的主要功能是负责复制原函数的一些属性,如 moudle、name、doc 等。如果不加 update_wrapper(), 那么被装饰器修饰的函数就会丢失其上面的一些属性信息。具体看一个测试代码示例:from functools import update_wrapperdef test_wrapper(f): def wrapper_function(*args, **kwargs): """装饰函数,不保留原信息""" return f(*args, **kwargs) return wrapper_functiondef test_update_wrapper(f): def wrapper_function(*args, **kwargs): """装饰函数,使用update_wrapper()方法保留原信息""" return f(*args, **kwargs) update_wrapper(wrapper_function, f) return wrapper_function@test_wrapperdef test_wrapped(): """被装饰的函数""" pass@test_update_wrapperdef test_update_wrapped(): """被装饰的函数,使用了update_wrapper()方法""" passprint('不使用update_wrapper()方法:')print(test_wrapped.__doc__) print(test_wrapped.__name__) print()print('使用update_wrapper()方法:')print(test_update_wrapped.__doc__) print(test_update_wrapped.__name__) 执行结果如下:不使用update_wrapper()方法:装饰函数,不保留原信息wrapper_function使用update_wrapper()方法:被装饰的函数,使用了update_wrapper()方法test_update_wrapped可以看到,不使用 update_wrapper() 方法的话,函数在使用装饰器后,它的一些基本属性比如 __name__ 等都是正真执行函数(比如上面的 wrapper_function() 函数)的属性。不过这个函数在分析视图函数的处理流程上并不重要。接下来看 as_view 中定义的 view() 方法,它是真正执行 HTTP 请求的视图函数:def view(request, *args, **kwargs): self = cls(**initkwargs) # 如果有get方法而没有head方法,对于head请求则直接使用get()方法进行处理 if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get # 将Django对应传过来的请求实例以及相应参数赋给实例属性 self.setup(request, *args, **kwargs) # 如果没有request属性,表明可能重写了setup()方法,而且setup()里面忘记了调用super() if not hasattr(self, 'request'): raise AttributeError( "%s instance has no 'request' attribute. Did you override " "setup() and forget to call super()?" % cls.__name__ ) # 调用dispatch()方法 return self.dispatch(request, *args, **kwargs)view() 方法里面会调用 setup() 方法将 Django 给视图函数传递的参数赋给实例变量,然后会调用 dispatch()方法去处理请求。两个函数的代码如下:def setup(self, request, *args, **kwargs): """Initialize attributes shared by all view methods.""" self.request = request self.args = args self.kwargs = kwargsdef dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)这里最核心的就是这个 dispatch() 方法了。首先该方法通过 request.method.lower() 这个可以拿到 http 的请求方式,比如 get、post、put 等,然后判断是不是在预先定义好的请求方式的列表中。如果满足,那么最核心的代码来了:handler = getattr(self, request.method.lower(), self.http_method_not_allowed)假设客户端发的是 get 请求,那么 request.method.lower() 就是 “get” ,接下来执行上面的代码,就会得到我们定义的视图类中定义的 get 函数,最后返回的是这个函数的处理结果。这就是为啥 get 请求能对应到视图函数中get() 方法的原因。其他的请求也是类似的,如果是不支持的请求,则会执行 http_method_not_allowed() 方法。return handler(request, *args, **kwargs)如果对这部分代码的执行流程还有疑问的,我们可以在 Django 的源码中添加几个 print() 函数,然后通过实际请求来看看执行过程:[root@server first_django_app]# cat ~/.pyenv/versions/django-manual/lib/python3.8/site-packages/django/views/generic/base.py class View: ... @classonlymethod def as_view(cls, **initkwargs): ... def view(request, *args, **kwargs): print('调用view函数处理请求') ... ... def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. print('调用dispatch()方法处理http请求,请求方式:{}'.format(request.method.lower())) if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) print('得到的handler:{}'.format(handler)) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)接下来我们还是使用前面定义的视图类 TestView 来进行操作,操作过程以及实验结果如下:# 一个窗口启动 django 工程(django-manual) [root@server first_django_app]# python manage.py runserver 0.0.0.0:8888Watching for file changes with StatReloaderPerforming system checks...System check identified no issues (0 silenced).April 15, 2020 - 04:30:04Django version 2.2.11, using settings 'first_django_app.settings'Starting development server at http://0.0.0.0:8888/Quit the server with CONTROL-C.# 另一个窗口发送http请求[root@server django-manual]# curl -XGET http://127.0.0.1:8888/hello/test-cbv/hello, get[root@server django-manual]# curl -XPOST http://127.0.0.1:8888/hello/test-cbv/hello, post[root@server django-manual]# curl -XPUT http://127.0.0.1:8888/hello/test-cbv/hello, put[root@server django-manual]# curl -XDELETE http://127.0.0.1:8888/hello/test-cbv/hello, delete
generic相关搜索
-
g area
gamma函数
gcc 下载
generic
genymotion
gesture
getattribute
getchar
getdocument
getelementbyid
getelementsbytagname
getmonth
getproperty
gets
getty
git clone
git pull
git push f
git 命令
git 使用