Compare commits
	
		
			31 Commits 
		
	
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								 | 
						ad792ec329 | 2 months ago | 
| 
							
							
								 | 
						727232a743 | 1 year ago | 
| 
							
							
								 | 
						29965eb4f2 | 3 years ago | 
| 
							
							
								 | 
						db7cf6acfb | 3 years ago | 
| 
							
							
								 | 
						e7adc08b5b | 3 years ago | 
| 
							
							
								 | 
						fbe3e1a5cc | 3 years ago | 
| 
							
							
								 | 
						942efdba4b | 4 years ago | 
| 
							
							
								 | 
						63ebc19b17 | 4 years ago | 
| 
							
							
								 | 
						d8e527b7e7 | 4 years ago | 
| 
							
							
								 | 
						1fd77e8f23 | 4 years ago | 
| 
							
							
								 | 
						834933aa17 | 4 years ago | 
| 
							
							
								 | 
						9a4260fa0d | 4 years ago | 
| 
							
							
								 | 
						eff0d3f065 | 4 years ago | 
| 
							
							
								 | 
						bee8db3813 | 4 years ago | 
| 
							
							
								 | 
						c9d382722a | 4 years ago | 
| 
							
							
								 | 
						a57721cf90 | 4 years ago | 
| 
							
							
								 | 
						0f0eaafbb9 | 4 years ago | 
| 
							
							
								 | 
						040ec60e8f | 4 years ago | 
| 
							
							
								 | 
						e7cd2bcd9f | 4 years ago | 
| 
							
							
								 | 
						99e4a5982f | 5 years ago | 
| 
							
							
								 | 
						f689dce846 | 5 years ago | 
| 
							
							
								 | 
						279916ae07 | 5 years ago | 
| 
							
							
								 | 
						617ee68288 | 5 years ago | 
| 
							
							
								 | 
						50f4ffb7f2 | 5 years ago | 
| 
							
							
								 | 
						8ddc99be82 | 5 years ago | 
| 
							
							
								 | 
						cc8f7d218f | 5 years ago | 
| 
							
							
								 | 
						c5cbf8230f | 5 years ago | 
| 
							
							
								 | 
						d1008dc495 | 5 years ago | 
| 
							
							
								 | 
						062b45870b | 5 years ago | 
| 
							
							
								 | 
						79c3d000fc | 5 years ago | 
| 
							
							
								 | 
						e2d82ae952 | 6 years ago | 
				 91 changed files with 1162 additions and 4768 deletions
			
			
		@ -1,166 +1,13 @@ | 
				
			|||||||
# DotXxlJob | 
					# Kingo.XxlJob.Core | 
				
			||||||
xxl-job的dotnet core 执行器实现,支持XXL-JOB 2.0+ | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 1 XXL-JOB概述 | 
					该仓库,基于 https://github.com/xuanye/DotXxlJob 源码基础上,进行扩展改造,原始项目说明,见   [README_SRC.md](README_SRC.md) 。 | 
				
			||||||
[XXL-JOB][1]是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。以下是它的架构图 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					更新内容: | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. 修复IJobHandler 注册 AddTransient瞬时服务注册,瞬时不起作用的情况。(2025.2.26) | 
				
			||||||
 | 
					
 | 
				
			||||||
## 2. 关于DotXxlJob产生 | 
					示例:GTYPackageJobService 服务的 Push_Common_Job 、GetJobNames 重写,原先 GetJobNames  虽然是Transient服务,任务Execute会执行多次,但是GetJobNames  之前只会执行一次,调整后会执行多次。 | 
				
			||||||
在工作中调研过多个任务调度平台,如Hangfire、基于Quatz.NET的第三方扩展,都与实际的需求有一点差距。 之前一直使用Hangfire,Hangfire的执行器在同步调用业务服务时,如果即时业务服务正在重新部署或者重启,有一定概率会出现死锁,导致CPU100%,后来全部调整为异步,但是这样就无法获得执行结果,这样的设计有蛮大问题,XxlJob的回调机制很好的解决了这个问题。本身如果通过http的方式调用,只要部署springbootd的一个执行器就可以解决问题,但是扩展性较差。所以萌生了实现DotNet版本的执行器的想法,为避免重复造轮子,开始之前也进行过调研,以下仓库[https://github.com/yuniansheng/xxl-job-dotnet][2]给了较大的启发,但是该库只支持1.9版本的xxljob,还有一些其他小问题,所以还是自力更生。 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 3. 如何使用 | 
					2. JobExecuteContext下 的 IJobLogger 增加 LogId 属性,用于通过 LogId 查看Job日志。(2025.2.26) | 
				
			||||||
 | 
					
 | 
				
			||||||
目前只实现了BEAN的方式,即直接实现IJobHandler调用的方式,Glue源码的方式实际上实现起来也并不复杂(有需求再说把),或者各位有需求Fork 实现一下 | 
					示例:任务执行后,可能有异常,有时找不到在哪次执行,可记录LogId,后续通过访问链接地址查看当时执行的日志。如 LogId 是 478571085,可访问对应的xjob服务的日志链接地址:https://xxx/xxl-job-admin/joblog/logDetailPage?id=478571085 | 
				
			||||||
 | 
					 | 
				
			||||||
可参考sample | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
安装: | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
> dotnet add package DotXxlJob.Core  | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### 3.1 在AspNetCore中使用 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
1. 声明一个AspNet的Middleware中间件,并扩展ApplicationBuilder,本质是拦截Post请求,解析Body中的流信息 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
``` | 
					 | 
				
			||||||
public class XxlJobExecutorMiddleware | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    private readonly IServiceProvider _provider; | 
					 | 
				
			||||||
    private readonly RequestDelegate _next; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private readonly XxlRpcServiceHandler _rpcService; | 
					 | 
				
			||||||
    public XxlJobExecutorMiddleware(IServiceProvider provider, RequestDelegate next) | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        this._provider = provider; | 
					 | 
				
			||||||
        this._next = next; | 
					 | 
				
			||||||
        this._rpcService = _provider.GetRequiredService<XxlRpcServiceHandler>(); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public async Task Invoke(HttpContext context) | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ("POST".Equals(context.Request.Method, StringComparison.OrdinalIgnoreCase) &&  | 
					 | 
				
			||||||
            "application/octet-stream".Equals(context.Request.ContentType, StringComparison.OrdinalIgnoreCase)) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var rsp =  await _rpcService.HandlerAsync(context.Request.Body); | 
					 | 
				
			||||||
            context.Response.StatusCode = (int) HttpStatusCode.OK; | 
					 | 
				
			||||||
            context.Response.ContentType = "text/plain;utf-8"; | 
					 | 
				
			||||||
            await context.Response.Body.WriteAsync(rsp,0,rsp.Length); | 
					 | 
				
			||||||
            return; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
        await _next.Invoke(context); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
``` | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
扩展ApplicationBuilderExtensions,可根据实际情况绑定在特殊的Url Path上 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
``` | 
					 | 
				
			||||||
public static class ApplicationBuilderExtensions | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public static IApplicationBuilder UseXxlJobExecutor(this IApplicationBuilder @this) | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
       return @this.UseMiddleware<XxlJobExecutorMiddleware>(); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
``` | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
在Startup中添加必要的引用,其中自动注册。 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
``` | 
					 | 
				
			||||||
public class Startup | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public Startup(IConfiguration configuration) | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        Configuration = configuration; | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private IConfiguration Configuration { get; } | 
					 | 
				
			||||||
     | 
					 | 
				
			||||||
    public void ConfigureServices(IServiceCollection services) | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
       | 
					 | 
				
			||||||
        services.AddXxlJobExecutor(Configuration); | 
					 | 
				
			||||||
        services.AddSingleton<IJobHandler, DemoJobHandler>(); // 添加自定义的jobHandler | 
					 | 
				
			||||||
        services.AddAutoRegistry(); // 自动注册 | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void Configure(IApplicationBuilder app,IHostingEnvironment env) | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        //启用XxlExecutor | 
					 | 
				
			||||||
        app.UseXxlJobExecutor(); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
``` | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
编写JobHandler,继承AbstractJobHandler或者直接实现接口IJobHandler,通过context.JobLogger 记录执行过程和结果,在AdminWeb上可查看的哦 | 
					 | 
				
			||||||
``` | 
					 | 
				
			||||||
[JobHandler("demoJobHandler")] | 
					 | 
				
			||||||
public class DemoJobHandler:AbstractJobHandler | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public override Task<ReturnT> Execute(JobExecuteContext context) | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        context.JobLogger.Log("receive demo job handler,parameter:{0}",context.JobParameter); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return Task.FromResult(ReturnT.SUCCESS); | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
``` | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## 3.2 配置信息 | 
					 | 
				
			||||||
管理端地址和端口是必填信息,其他根据实际情况,选择配置,配置项说明见下代码中的注释 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
``` | 
					 | 
				
			||||||
 public class XxlJobExecutorOptions | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    | 
					 | 
				
			||||||
    /// <summary> | 
					 | 
				
			||||||
    /// 管理端地址,多个以;分隔 | 
					 | 
				
			||||||
    /// </summary> | 
					 | 
				
			||||||
    public string AdminAddresses { get; set; } | 
					 | 
				
			||||||
    /// <summary> | 
					 | 
				
			||||||
    /// appName自动注册时要去管理端配置一致 | 
					 | 
				
			||||||
    /// </summary> | 
					 | 
				
			||||||
    public string AppName { get; set; } = "xxl-job-executor-dotnet"; | 
					 | 
				
			||||||
    /// <summary> | 
					 | 
				
			||||||
    /// 自动注册时提交的地址,为空会自动获取内网地址 | 
					 | 
				
			||||||
    /// </summary> | 
					 | 
				
			||||||
    public string SpecialBindAddress { get; set; } | 
					 | 
				
			||||||
    /// <summary> | 
					 | 
				
			||||||
    /// 绑定端口 | 
					 | 
				
			||||||
    /// </summary> | 
					 | 
				
			||||||
    public int Port { get; set; } | 
					 | 
				
			||||||
    /// <summary> | 
					 | 
				
			||||||
    /// 是否自动注册 | 
					 | 
				
			||||||
    /// </summary> | 
					 | 
				
			||||||
    public bool AutoRegistry { get; set; } | 
					 | 
				
			||||||
    /// <summary> | 
					 | 
				
			||||||
    /// 认证票据 | 
					 | 
				
			||||||
    /// </summary> | 
					 | 
				
			||||||
    public string AccessToken { get; set; } | 
					 | 
				
			||||||
    /// <summary> | 
					 | 
				
			||||||
    /// 日志目录,默认为执行目录的logs子目录下,请配置绝对路径 | 
					 | 
				
			||||||
    /// </summary> | 
					 | 
				
			||||||
    public string LogPath { get; set; } = Path.Combine(AppContext.BaseDirectory, "./logs"); | 
					 | 
				
			||||||
    /// <summary> | 
					 | 
				
			||||||
    /// 日志保留天数 | 
					 | 
				
			||||||
    /// </summary> | 
					 | 
				
			||||||
    public int LogRetentionDays { get; set; } = 30; | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
``` | 
					 | 
				
			||||||
## 在其他Http服务中使用 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
只需要实现Http请求的拦截,并判断post请求中content-Type="application/octet-stream",并使用XxlRpcServiceHandler来处理流 即可。 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## 其他说明 | 
					 | 
				
			||||||
XXL-JOB内置的RPC是使用Hessian协议,这个有点坑。很多都是java特有的属性和标识,比如类名什么的。在本项目中,并没有实现完整的Hessian2协议,只实现了使用到的类型,当然扩展起来也非常方便。如果有人要单独使用Hessian 这个类库的话,要特别注意这个问题。 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
有任何问题,可Issue反馈 ,最后感谢 xxl-job | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [1]: http://www.xuxueli.com/xxl-job | 
					 | 
				
			||||||
  [2]: https://github.com/yuniansheng/xxl-job-dotnet | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,168 @@ | 
				
			|||||||
 | 
					# DotXxlJob | 
				
			||||||
 | 
					xxl-job的dotnet core 最新执行器实现,支持XXL-JOB 2.2+  | 
				
			||||||
 | 
					> 注意XXL-JOB 2.0.1版本请使用 1.0.8的执行器实现 ,*xxl-job* 从 2.0.2 到2.2版本又使用了xxl-rpc的新协议,本执行器不做支持,确实需要的朋友请自行fork..  | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 1 XXL-JOB概述 | 
				
			||||||
 | 
					[XXL-JOB][1]是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。以下是它的架构图 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2. 关于DotXxlJob产生 | 
				
			||||||
 | 
					在工作中调研过多个任务调度平台,如Hangfire、基于Quatz.NET的第三方扩展,都与实际的需求有一点差距。 之前一直使用Hangfire,Hangfire的执行器在同步调用业务服务时,如果即时业务服务正在重新部署或者重启,有一定概率会出现死锁,导致CPU100%,后来全部调整为异步,但是这样就无法获得执行结果,这样的设计有蛮大问题,XxlJob的回调机制很好的解决了这个问题。本身如果通过http的方式调用,只要部署springbootd的一个执行器就可以解决问题,但是扩展性较差。所以萌生了实现DotNet版本的执行器的想法,为避免重复造轮子,开始之前也进行过调研,以下仓库[https://github.com/yuniansheng/xxl-job-dotnet][2]给了较大的启发,但是该库只支持1.9版本的xxljob,还有一些其他小问题,所以还是自力更生。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3. 如何使用 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					目前只实现了BEAN的方式,即直接实现IJobHandler调用的方式,Glue源码的方式实际上实现起来也并不复杂(有需求再说把),或者各位有需求Fork 实现一下 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					可参考sample | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					安装: | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> dotnet add package DotXxlJob.Core  | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 3.1 在AspNetCore中使用 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. 声明一个AspNet的Middleware中间件,并扩展ApplicationBuilder,本质是拦截Post请求,解析Body中的流信息 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					 public class XxlJobExecutorMiddleware | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        private readonly IServiceProvider _provider; | 
				
			||||||
 | 
					        private readonly RequestDelegate _next; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private readonly XxlRestfulServiceHandler _rpcService; | 
				
			||||||
 | 
					        public XxlJobExecutorMiddleware(IServiceProvider provider, RequestDelegate next) | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					            this._provider = provider; | 
				
			||||||
 | 
					            this._next = next; | 
				
			||||||
 | 
					            this._rpcService = _provider.GetRequiredService<XxlRestfulServiceHandler>(); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task Invoke(HttpContext context) | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					            string contentType = context.Request.ContentType; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ("POST".Equals(context.Request.Method, StringComparison.OrdinalIgnoreCase) | 
				
			||||||
 | 
					                && !string.IsNullOrEmpty(contentType) | 
				
			||||||
 | 
					                && contentType.ToLower().StartsWith("application/json")) | 
				
			||||||
 | 
					            { | 
				
			||||||
 | 
					             | 
				
			||||||
 | 
					                await _rpcService.HandlerAsync(context.Request,context.Response);               | 
				
			||||||
 | 
					             | 
				
			||||||
 | 
					                return; | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					             | 
				
			||||||
 | 
					            await _next.Invoke(context); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					扩展ApplicationBuilderExtensions,可根据实际情况绑定在特殊的Url Path上 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					public static class ApplicationBuilderExtensions | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					    public static IApplicationBuilder UseXxlJobExecutor(this IApplicationBuilder @this) | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					       return @this.UseMiddleware<XxlJobExecutorMiddleware>(); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在Startup中添加必要的引用,其中自动注册。 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					public class Startup | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					    public Startup(IConfiguration configuration) | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        Configuration = configuration; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private IConfiguration Configuration { get; } | 
				
			||||||
 | 
					     | 
				
			||||||
 | 
					    public void ConfigureServices(IServiceCollection services) | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					       | 
				
			||||||
 | 
					        services.AddXxlJobExecutor(Configuration); | 
				
			||||||
 | 
					        services.AddSingleton<IJobHandler, DemoJobHandler>(); // 添加自定义的jobHandler | 
				
			||||||
 | 
					        services.AddAutoRegistry(); // 自动注册 | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void Configure(IApplicationBuilder app,IHostingEnvironment env) | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        //启用XxlExecutor | 
				
			||||||
 | 
					        app.UseXxlJobExecutor(); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					编写JobHandler,继承AbstractJobHandler或者直接实现接口IJobHandler,通过context.JobLogger 记录执行过程和结果,在AdminWeb上可查看的哦 | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					[JobHandler("demoJobHandler")] | 
				
			||||||
 | 
					public class DemoJobHandler:AbstractJobHandler | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					    public override Task<ReturnT> Execute(JobExecuteContext context) | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					        context.JobLogger.Log("receive demo job handler,parameter:{0}",context.JobParameter); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Task.FromResult(ReturnT.SUCCESS); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3.2 配置信息 | 
				
			||||||
 | 
					管理端地址和端口是必填信息,其他根据实际情况,选择配置,配置项说明见下代码中的注释 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					 public class XxlJobExecutorOptions | 
				
			||||||
 | 
					{ | 
				
			||||||
 | 
					    | 
				
			||||||
 | 
					    /// <summary> | 
				
			||||||
 | 
					    /// 管理端地址,多个以;分隔 | 
				
			||||||
 | 
					    /// </summary> | 
				
			||||||
 | 
					    public string AdminAddresses { get; set; } | 
				
			||||||
 | 
					    /// <summary> | 
				
			||||||
 | 
					    /// appName自动注册时要去管理端配置一致 | 
				
			||||||
 | 
					    /// </summary> | 
				
			||||||
 | 
					    public string AppName { get; set; } = "xxl-job-executor-dotnet"; | 
				
			||||||
 | 
					    /// <summary> | 
				
			||||||
 | 
					    /// 自动注册时提交的地址,为空会自动获取内网地址 | 
				
			||||||
 | 
					    /// </summary> | 
				
			||||||
 | 
					    public string SpecialBindAddress { get; set; } | 
				
			||||||
 | 
					    /// <summary> | 
				
			||||||
 | 
					    /// 绑定端口 | 
				
			||||||
 | 
					    /// </summary> | 
				
			||||||
 | 
					    public int Port { get; set; } | 
				
			||||||
 | 
					    /// <summary> | 
				
			||||||
 | 
					    /// 是否自动注册 | 
				
			||||||
 | 
					    /// </summary> | 
				
			||||||
 | 
					    public bool AutoRegistry { get; set; } | 
				
			||||||
 | 
					    /// <summary> | 
				
			||||||
 | 
					    /// 认证票据 | 
				
			||||||
 | 
					    /// </summary> | 
				
			||||||
 | 
					    public string AccessToken { get; set; } | 
				
			||||||
 | 
					    /// <summary> | 
				
			||||||
 | 
					    /// 日志目录,默认为执行目录的logs子目录下,请配置绝对路径 | 
				
			||||||
 | 
					    /// </summary> | 
				
			||||||
 | 
					    public string LogPath { get; set; } = Path.Combine(AppContext.BaseDirectory, "./logs"); | 
				
			||||||
 | 
					    /// <summary> | 
				
			||||||
 | 
					    /// 日志保留天数 | 
				
			||||||
 | 
					    /// </summary> | 
				
			||||||
 | 
					    public int LogRetentionDays { get; set; } = 30; | 
				
			||||||
 | 
					} | 
				
			||||||
 | 
					``` | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 其他说明 | 
				
			||||||
 | 
					注意XXL-JOB 2.0.1版本请使用 1.0.8的执行器实现 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					有任何问题,可Issue反馈 ,最后感谢 xxl-job | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [1]: http://www.xuxueli.com/xxl-job | 
				
			||||||
 | 
					  [2]: https://github.com/yuniansheng/xxl-job-dotnet | 
				
			||||||
@ -1,10 +1,10 @@ | 
				
			|||||||
<Project> | 
					<Project> | 
				
			||||||
	<PropertyGroup> | 
						<PropertyGroup> | 
				
			||||||
		<DotXxlJobPackageNotes> | 
							<DotXxlJobPackageNotes> | 
				
			||||||
		1. 修复回调一次过多的问题 | 
							1. 修改异步方式读取RequestBody  | 
				
			||||||
 | 
							2. 兼容xxl-jobv2.3版本回调函数参数变更的问题 | 
				
			||||||
 | 
							3. 修复阻塞处理策略设置为“丢弃后续调度“,只有第一次调度正常执行,后面的所有调度都被丢弃了的问题 | 
				
			||||||
 | 
							4. 任务取消支持 (pullrequest#24) | 
				
			||||||
		</DotXxlJobPackageNotes> 		 | 
							</DotXxlJobPackageNotes> 		 | 
				
			||||||
		<HessianPackageNotes> | 
					 | 
				
			||||||
		1. 实现基本的Hessian协议 | 
					 | 
				
			||||||
		</HessianPackageNotes>  | 
					 | 
				
			||||||
	</PropertyGroup> | 
						</PropertyGroup> | 
				
			||||||
</Project> | 
					</Project> | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,5 @@ | 
				
			|||||||
<Project> | 
					<Project> | 
				
			||||||
	<PropertyGroup> | 
						<PropertyGroup> | 
				
			||||||
		<DotXxlJobPackageVersion>1.0.8</DotXxlJobPackageVersion>	 | 
							<DotXxlJobPackageVersion>2.3.2</DotXxlJobPackageVersion> | 
				
			||||||
		<HessianPackageVersion>1.0.1</HessianPackageVersion>		 | 
					 | 
				
			||||||
	</PropertyGroup> | 
						</PropertyGroup> | 
				
			||||||
</Project> | 
					</Project> | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,13 @@ | 
				
			|||||||
 | 
					{ | 
				
			||||||
 | 
					  "version": 1, | 
				
			||||||
 | 
					  "isRoot": true, | 
				
			||||||
 | 
					  "tools": { | 
				
			||||||
 | 
					    "dotnet-ef": { | 
				
			||||||
 | 
					      "version": "8.0.7", | 
				
			||||||
 | 
					      "commands": [ | 
				
			||||||
 | 
					        "dotnet-ef" | 
				
			||||||
 | 
					      ], | 
				
			||||||
 | 
					      "rollForward": false | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					} | 
				
			||||||
@ -1,27 +1,12 @@ | 
				
			|||||||
{ | 
					{ | 
				
			||||||
  "iisSettings": { | 
					 | 
				
			||||||
    "windowsAuthentication": false, | 
					 | 
				
			||||||
    "anonymousAuthentication": true, | 
					 | 
				
			||||||
    "iisExpress": { | 
					 | 
				
			||||||
      "applicationUrl": "http://localhost:60087/", | 
					 | 
				
			||||||
      "sslPort": 0 | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
  }, | 
					 | 
				
			||||||
  "profiles": { | 
					  "profiles": { | 
				
			||||||
    "IIS Express": { | 
					 | 
				
			||||||
      "commandName": "IISExpress", | 
					 | 
				
			||||||
      "launchBrowser": true, | 
					 | 
				
			||||||
      "environmentVariables": { | 
					 | 
				
			||||||
        "ASPNETCORE_ENVIRONMENT": "Development" | 
					 | 
				
			||||||
      } | 
					 | 
				
			||||||
    }, | 
					 | 
				
			||||||
    "ASPNetCoreExecutor": { | 
					    "ASPNetCoreExecutor": { | 
				
			||||||
      "commandName": "Project", | 
					      "commandName": "Project", | 
				
			||||||
      "launchBrowser": true, | 
					      "launchBrowser": true, | 
				
			||||||
      "environmentVariables": { | 
					      "environmentVariables": { | 
				
			||||||
        "ASPNETCORE_ENVIRONMENT": "Development" | 
					        "ASPNETCORE_ENVIRONMENT": "Development" | 
				
			||||||
      }, | 
					      }, | 
				
			||||||
      "applicationUrl": "http://localhost:60088/" | 
					      "applicationUrl": "http://localhost:6662/" | 
				
			||||||
    } | 
					    } | 
				
			||||||
  } | 
					  } | 
				
			||||||
} | 
					} | 
				
			||||||
@ -1,17 +1,16 @@ | 
				
			|||||||
{ | 
					{ | 
				
			||||||
  "Logging": { | 
					  "Logging": { | 
				
			||||||
    "LogLevel": { | 
					    "LogLevel": { | 
				
			||||||
      "Default": "Warning" | 
					      "Default": "Information" | 
				
			||||||
    } | 
					    } | 
				
			||||||
  }, | 
					  }, | 
				
			||||||
  "xxlJob": { | 
					  "xxlJob": { | 
				
			||||||
    "adminAddresses":"http://127.0.0.1:8080", | 
					    "adminAddresses": "https://jobs.xuanye.wang/xxl-job-admin", | 
				
			||||||
    "appName": "xxl-job-executor-dotnet", | 
					    "appName": "xxl-job-executor-dotnet", | 
				
			||||||
    "specialBindAddress": "127.0.0.1", | 
					    "specialBindAddress": "127.0.0.1", | 
				
			||||||
    "port": 5000, | 
					    "port": 6662, | 
				
			||||||
    "autoRegistry":false, | 
					    "autoRegistry": true, | 
				
			||||||
    "accessToken": "", | 
					    "accessToken": "", | 
				
			||||||
    "logRetentionDays": 30 | 
					    "logRetentionDays": 30 | 
				
			||||||
  } | 
					  } | 
				
			||||||
  | 
					 | 
				
			||||||
} | 
					} | 
				
			||||||
@ -1,73 +0,0 @@ | 
				
			|||||||
------------ 0x43---------------- | 
					 | 
				
			||||||
ReadClassDefinition | 
					 | 
				
			||||||
Hessian.ClassDef={"Name":"com.xxl.rpc.remoting.net.params.XxlRpcRequest","Fields":["requestId","createMillisTime","accessToken","className","methodName","version","parameterTypes","parameters"]} | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
------------ 0x60---------------- | 
					 | 
				
			||||||
ReadObjectCompact  XxlRpcRequest | 
					 | 
				
			||||||
------------ 0x30---------------- | 
					 | 
				
			||||||
ReadMediumString   requestId | 
					 | 
				
			||||||
------------ 0x4c---------------- | 
					 | 
				
			||||||
ReadLongFull       createMillisTime | 
					 | 
				
			||||||
------------ 0x00---------------- | 
					 | 
				
			||||||
ReadShortString    accessToken | 
					 | 
				
			||||||
------------ 0x1d---------------- | 
					 | 
				
			||||||
ReadShortString    className | 
					 | 
				
			||||||
------------ 0x08---------------- | 
					 | 
				
			||||||
ReadShortString    methodName | 
					 | 
				
			||||||
------------ 0x4e---------------- | 
					 | 
				
			||||||
ReadNull           version | 
					 | 
				
			||||||
------------ 0x71---------------- | 
					 | 
				
			||||||
ReadCompactFixList parameterTypes | 
					 | 
				
			||||||
------------ 0x43---------------- | 
					 | 
				
			||||||
ReadClassDefinition java.lang.Class | 
					 | 
				
			||||||
------------ 0x61---------------- | 
					 | 
				
			||||||
ReadObjectCompact java.lang.Class | 
					 | 
				
			||||||
------------ 0x0e---------------- | 
					 | 
				
			||||||
ReadShortString name | 
					 | 
				
			||||||
Hessian.HessianObject=[{"Item1":"requestId","Item2":"e24123be4a76417ca6f41f227532b235"},{"Item1":"createMillisTime","Item2":1547819469003},{"Item1":"accessToken","Item2":""},{"Item1":"className","Item2":"com.xxl.job.core.biz.AdminBiz"},{"It | 
					 | 
				
			||||||
em1":"methodName","Item2":"callback"},{"Item1":"version","Item2":null},{"Item1":"parameterTypes","Item2":[{"Name":"java.lang.Class","Fields":["name"]}]},{"Item1":"parameters","Item2":[{"Item1":"name","Item2":"java.util.List"}]}] | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
------------ 0x71---------------- | 
					 | 
				
			||||||
ReadCompactFixList  parameters | 
					 | 
				
			||||||
------------ 0x72---------------- | 
					 | 
				
			||||||
ReadCompactFixList  List | 
					 | 
				
			||||||
------------ 0x43---------------- | 
					 | 
				
			||||||
ReadClassDefinition HandleCallbackParam | 
					 | 
				
			||||||
------------ 0x62---------------- | 
					 | 
				
			||||||
ReadObjectCompact HandleCallbackParam | 
					 | 
				
			||||||
------------ 0x9b---------------- | 
					 | 
				
			||||||
ReadIntegerSingleByte logId | 
					 | 
				
			||||||
------------ 0x4c---------------- | 
					 | 
				
			||||||
ReadLongFull  logDateTim | 
					 | 
				
			||||||
------------ 0x43---------------- | 
					 | 
				
			||||||
ReadClassDefinition executeResult | 
					 | 
				
			||||||
System.Collections.Generic.List`1[System.Object]=[[{"Name":"com.xxl.job.core.biz.model.HandleCallbackParam","Fields":["logId","logDateTim","executeResult"]},[{"Item1":"logId","Item2":11},{"Item1":"logDateTim","Item2":1547819469000},{"Item1" | 
					 | 
				
			||||||
:"executeResult","Item2":{"Name":"com.xxl.job.core.biz.model.ReturnT","Fields":["code","msg","content"]}}]]] | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
------------ 0x63---------------- | 
					 | 
				
			||||||
ReadObjectCompact   executeResult | 
					 | 
				
			||||||
------------ 0xc8---------------- | 
					 | 
				
			||||||
ReadIntegerTwoBytes code | 
					 | 
				
			||||||
------------ 0x03---------------- | 
					 | 
				
			||||||
ReadShortString msg | 
					 | 
				
			||||||
------------ 0x07---------------- | 
					 | 
				
			||||||
ReadShortString   content | 
					 | 
				
			||||||
Hessian.HessianObject=[{"Item1":"code","Item2":200},{"Item1":"msg","Item2":"1bc"},{"Item1":"content","Item2":"acd3323"}] | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
------------ 0x62---------------- | 
					 | 
				
			||||||
ReadObjectCompact HandleCallbackParam | 
					 | 
				
			||||||
------------ 0xa6---------------- | 
					 | 
				
			||||||
ReadIntegerSingleByte logId | 
					 | 
				
			||||||
------------ 0x4c---------------- | 
					 | 
				
			||||||
ReadLongFull  logDateTim | 
					 | 
				
			||||||
------------ 0x63---------------- | 
					 | 
				
			||||||
ReadObjectCompact executeResult | 
					 | 
				
			||||||
------------ 0xc9---------------- | 
					 | 
				
			||||||
ReadIntegerTwoBytes code | 
					 | 
				
			||||||
------------ 0x03---------------- | 
					 | 
				
			||||||
ReadShortString  msg | 
					 | 
				
			||||||
------------ 0x03---------------- | 
					 | 
				
			||||||
ReadShortString  content | 
					 | 
				
			||||||
Hessian.HessianObject=[{"Item1":"logId","Item2":22},{"Item1":"logDateTim","Item2":1547819469000},{"Item1":"executeResult","Item2":[{"Item1":"code","Item2":500},{"Item1":"msg","Item2":"cac"},{"Item1":"content","Item2":"aad"}]}] | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
@ -1,74 +0,0 @@ | 
				
			|||||||
--------------------------------------------------------------- | 
					 | 
				
			||||||
------------ 0x43---------------- | 
					 | 
				
			||||||
ReadClassDefinition | 
					 | 
				
			||||||
Hessian.ClassDef={"Name":"com.xxl.rpc.remoting.net.params.XxlRpcRequest","Fields":["requestId","createMillisTime","accessToken","className","methodName","version","parameterTypes","parameters"]} | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
------------ 0x60---------------- | 
					 | 
				
			||||||
ReadObjectCompact | 
					 | 
				
			||||||
------------ 0x30---------------- | 
					 | 
				
			||||||
ReadMediumString | 
					 | 
				
			||||||
------------ 0x4c---------------- | 
					 | 
				
			||||||
ReadLongFull | 
					 | 
				
			||||||
------------ 0x00---------------- | 
					 | 
				
			||||||
ReadShortString | 
					 | 
				
			||||||
------------ 0x1d---------------- | 
					 | 
				
			||||||
ReadShortString | 
					 | 
				
			||||||
------------ 0x08---------------- | 
					 | 
				
			||||||
ReadShortString | 
					 | 
				
			||||||
------------ 0x4e---------------- | 
					 | 
				
			||||||
ReadNull | 
					 | 
				
			||||||
------------ 0x71---------------- | 
					 | 
				
			||||||
ReadCompactFixList | 
					 | 
				
			||||||
------------ 0x43---------------- | 
					 | 
				
			||||||
ReadClassDefinition | 
					 | 
				
			||||||
------------ 0x61---------------- | 
					 | 
				
			||||||
ReadObjectCompact | 
					 | 
				
			||||||
------------ 0x0e---------------- | 
					 | 
				
			||||||
ReadShortString | 
					 | 
				
			||||||
Hessian.HessianObject=[{"Item1":"requestId","Item2":"e24123be4a76417ca6f41f227532b235"},{"Item1":"createMillisTime","Item2":1547819469003},{"Item1":"accessToken","Item2":""},{"Item1":"className","Item2":"com.xxl.job.core.biz.AdminBiz"},{"I | 
					 | 
				
			||||||
tem1":"methodName","Item2":"callback"},{"Item1":"version","Item2":null},{"Item1":"parameterTypes","Item2":[{"Name":"java.lang.Class","Fields":["name"]}]},{"Item1":"parameters","Item2":[{"Item1":"name","Item2":"java.util.List"}]}] | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
------------ 0x71---------------- | 
					 | 
				
			||||||
ReadCompactFixList | 
					 | 
				
			||||||
------------ 0x72---------------- | 
					 | 
				
			||||||
ReadCompactFixList | 
					 | 
				
			||||||
------------ 0x43---------------- | 
					 | 
				
			||||||
ReadClassDefinition | 
					 | 
				
			||||||
------------ 0x62---------------- | 
					 | 
				
			||||||
ReadObjectCompact | 
					 | 
				
			||||||
------------ 0x9b---------------- | 
					 | 
				
			||||||
ReadIntegerSingleByte | 
					 | 
				
			||||||
------------ 0x4c---------------- | 
					 | 
				
			||||||
ReadLongFull | 
					 | 
				
			||||||
------------ 0x43---------------- | 
					 | 
				
			||||||
ReadClassDefinition | 
					 | 
				
			||||||
System.Collections.Generic.List`1[System.Object]=[[{"Name":"com.xxl.job.core.biz.model.HandleCallbackParam","Fields":["logId","logDateTim","executeResult"]},[{"Item1":"logId","Item2":11},{"Item1":"logDateTim","Item2":1547819469000},{"Item1 | 
					 | 
				
			||||||
":"executeResult","Item2":{"Name":"com.xxl.job.core.biz.model.ReturnT","Fields":["code","msg","content"]}}]]] | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
------------ 0x63---------------- | 
					 | 
				
			||||||
ReadObjectCompact | 
					 | 
				
			||||||
------------ 0xc8---------------- | 
					 | 
				
			||||||
ReadIntegerTwoBytes | 
					 | 
				
			||||||
------------ 0x03---------------- | 
					 | 
				
			||||||
ReadShortString | 
					 | 
				
			||||||
------------ 0x07---------------- | 
					 | 
				
			||||||
ReadShortString | 
					 | 
				
			||||||
Hessian.HessianObject=[{"Item1":"code","Item2":200},{"Item1":"msg","Item2":"1bc"},{"Item1":"content","Item2":"acd3323"}] | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
------------ 0x62---------------- | 
					 | 
				
			||||||
ReadObjectCompact | 
					 | 
				
			||||||
------------ 0xa6---------------- | 
					 | 
				
			||||||
ReadIntegerSingleByte | 
					 | 
				
			||||||
------------ 0x4c---------------- | 
					 | 
				
			||||||
ReadLongFull | 
					 | 
				
			||||||
------------ 0x63---------------- | 
					 | 
				
			||||||
ReadObjectCompact | 
					 | 
				
			||||||
------------ 0xc9---------------- | 
					 | 
				
			||||||
ReadIntegerTwoBytes | 
					 | 
				
			||||||
------------ 0x03---------------- | 
					 | 
				
			||||||
ReadShortString | 
					 | 
				
			||||||
------------ 0x03---------------- | 
					 | 
				
			||||||
ReadShortString | 
					 | 
				
			||||||
Hessian.HessianObject=[{"Item1":"logId","Item2":22},{"Item1":"logDateTim","Item2":1547819469000},{"Item1":"executeResult","Item2":[{"Item1":"code","Item2":500},{"Item1":"msg","Item2":"aad"},{"Item1":"content","Item2":"cac"}]}] | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
------------------------------------------------------------ | 
					 | 
				
			||||||
									
										Binary file not shown.
									
								
							
						
									
										Binary file not shown.
									
								
							
						
									
										Binary file not shown.
									
								
							
						
									
										Binary file not shown.
									
								
							
						@ -1,18 +0,0 @@ | 
				
			|||||||
set -ex | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cd $(dirname $0)/../ | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
artifactsFolder="./artifacts" | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ -d $artifactsFolder ]; then | 
					 | 
				
			||||||
  rm -R $artifactsFolder | 
					 | 
				
			||||||
fi | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mkdir -p $artifactsFolder | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dotnet build ./src/Hessian/Hessian.csproj -c Release | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dotnet pack ./src/Hessian/Hessian.csproj -c Release -o ../../$artifactsFolder | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dotnet nuget push ./$artifactsFolder/Hessian.*.nupkg -k $NUGET_KEY -s https://www.nuget.org | 
					 | 
				
			||||||
@ -1,132 +0,0 @@ | 
				
			|||||||
using System; | 
					 | 
				
			||||||
using System.Collections; | 
					 | 
				
			||||||
using System.Collections.Generic; | 
					 | 
				
			||||||
using System.Reflection; | 
					 | 
				
			||||||
using System.Runtime.Serialization; | 
					 | 
				
			||||||
using DotXxlJob.Core.Model; | 
					 | 
				
			||||||
using Hessian; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace DotXxlJob.Core | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public class HessianObjectHelper | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        private static readonly Dictionary<string,Dictionary<string,PropertyInfo>> TransferObjCache  | 
					 | 
				
			||||||
            = new Dictionary<string, Dictionary<string, PropertyInfo>>(); | 
					 | 
				
			||||||
        private static readonly Dictionary<string,Type> TransferTypeCache  | 
					 | 
				
			||||||
            = new Dictionary<string, Type>(); | 
					 | 
				
			||||||
        static HessianObjectHelper() | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
            InitProperties(typeof(RpcRequest)); | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            InitProperties(typeof(TriggerParam)); | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            InitProperties(typeof(RpcResponse)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            InitProperties(typeof(ReturnT)); | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            InitProperties(typeof(HandleCallbackParam)); | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            InitProperties(typeof(JavaClass)); | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            InitProperties(typeof(RegistryParam)); | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            InitProperties(typeof(LogResult)); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
        private static void InitProperties(Type type) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var propertyInfos = new Dictionary<string, PropertyInfo>(); | 
					 | 
				
			||||||
            var typeInfo = type.GetTypeInfo(); | 
					 | 
				
			||||||
            var classAttr = type.GetCustomAttribute<DataContractAttribute>(); | 
					 | 
				
			||||||
            if (classAttr == null) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            foreach (var property in typeInfo.DeclaredProperties) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                var attribute = property.GetCustomAttribute<DataMemberAttribute>(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (null == attribute) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    continue; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (!property.CanRead || !property.CanWrite) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    continue; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                propertyInfos.Add(attribute.Name,property); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            TransferTypeCache.Add(classAttr.Name,type); | 
					 | 
				
			||||||
            TransferObjCache.Add(classAttr.Name,propertyInfos); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public static object GetRealObjectValue(Deserializer deserializer,object value) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (value == null || IsSimpleType(value.GetType())) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                return value; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (value is HessianObject hessianObject) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                if(TransferObjCache.TryGetValue(hessianObject.TypeName,out var properties)) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    var instance = Activator.CreateInstance(TransferTypeCache[hessianObject.TypeName]); | 
					 | 
				
			||||||
                    foreach (var (k, v) in hessianObject) | 
					 | 
				
			||||||
                    { | 
					 | 
				
			||||||
                        if (properties.TryGetValue(k, out var p)) | 
					 | 
				
			||||||
                        { | 
					 | 
				
			||||||
                            p.SetValue(instance,GetRealObjectValue(deserializer,v)); | 
					 | 
				
			||||||
                        } | 
					 | 
				
			||||||
                    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    return instance; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (value is ClassDef) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                return GetRealObjectValue(deserializer, deserializer.ReadValue()); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            if (IsListType(value.GetType())) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                var listData = new List<object>(); | 
					 | 
				
			||||||
                 | 
					 | 
				
			||||||
                var cList = value as List<object>; | 
					 | 
				
			||||||
                foreach (var cItem in cList) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                   listData.Add(GetRealObjectValue(deserializer,cItem)); | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return listData; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            | 
					 | 
				
			||||||
            throw new HessianException($"unknown item:{value.GetType()}"); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        private static bool IsListType(Type type) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            return typeof(ICollection).IsAssignableFrom(type);           | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
        private static bool IsSimpleType(Type typeInfo) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (typeInfo.IsValueType || typeInfo.IsEnum || typeInfo.IsPrimitive) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                return true; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (typeof (string) == typeInfo) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                return true; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return false; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,79 +0,0 @@ | 
				
			|||||||
using System; | 
					 | 
				
			||||||
using System.IO; | 
					 | 
				
			||||||
using DotXxlJob.Core.Model; | 
					 | 
				
			||||||
using Hessian; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace DotXxlJob.Core | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public static class HessianSerializer | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
      | 
					 | 
				
			||||||
        public static RpcRequest DeserializeRequest(Stream stream) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            RpcRequest request = null; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            try | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                var deserializer = new Deserializer(stream); | 
					 | 
				
			||||||
                var classDef = deserializer.ReadValue() as ClassDef;  | 
					 | 
				
			||||||
                if (!Constants.RpcRequestJavaFullName.Equals(classDef.Name)) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    throw  new HessianException($"unknown class :{classDef.Name}"); | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
                request = HessianObjectHelper.GetRealObjectValue(deserializer,deserializer.ReadValue()) as RpcRequest; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            catch (EndOfStreamException) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                //没有数据可读了 | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            return request; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
      | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        public static void SerializeRequest(Stream stream,RpcRequest req) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var serializer = new Serializer(stream); | 
					 | 
				
			||||||
            serializer.WriteObject(req); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        public static void SerializeResponse(Stream stream,RpcResponse res) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var serializer = new Serializer(stream); | 
					 | 
				
			||||||
            serializer.WriteObject(res); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
   | 
					 | 
				
			||||||
        public static RpcResponse DeserializeResponse(Stream resStream) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            RpcResponse rsp = null; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            try | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                var deserializer = new Deserializer(resStream); | 
					 | 
				
			||||||
                var classDef = deserializer.ReadValue() as ClassDef; | 
					 | 
				
			||||||
                if (!Constants.RpcResponseJavaFullName.Equals(classDef.Name)) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    throw new HessianException($"unknown class :{classDef.Name}"); | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                rsp = HessianObjectHelper.GetRealObjectValue(deserializer,deserializer.ReadValue()) as RpcResponse; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            catch (EndOfStreamException) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                //没有数据可读了 | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            catch | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                //TODO: do something? | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return rsp; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
       | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,13 +1,17 @@ | 
				
			|||||||
 | 
					using System.Threading; | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace DotXxlJob.Core.Model | 
					namespace DotXxlJob.Core.Model | 
				
			||||||
{ | 
					{ | 
				
			||||||
    public class JobExecuteContext | 
					    public class JobExecuteContext | 
				
			||||||
    { | 
					    { | 
				
			||||||
        public JobExecuteContext(IJobLogger jobLogger,string jobParameter) | 
					        public JobExecuteContext(IJobLogger jobLogger, string jobParameter, CancellationToken cancellationToken) | 
				
			||||||
        { | 
					        { | 
				
			||||||
            this.JobLogger = jobLogger; | 
					            this.JobLogger = jobLogger; | 
				
			||||||
            this.JobParameter = jobParameter; | 
					            this.JobParameter = jobParameter; | 
				
			||||||
 | 
					            this.cancellationToken = cancellationToken; | 
				
			||||||
        } | 
					        } | 
				
			||||||
        public string JobParameter { get; } | 
					        public string JobParameter { get; } | 
				
			||||||
        public IJobLogger JobLogger { get; } | 
					        public IJobLogger JobLogger { get; } | 
				
			||||||
 | 
					        public CancellationToken cancellationToken { get; } | 
				
			||||||
    } | 
					    } | 
				
			||||||
} | 
					} | 
				
			||||||
@ -1,217 +0,0 @@ | 
				
			|||||||
using System; | 
					 | 
				
			||||||
using System.Collections.Concurrent; | 
					 | 
				
			||||||
using System.IO; | 
					 | 
				
			||||||
using System.Linq; | 
					 | 
				
			||||||
using System.Reflection; | 
					 | 
				
			||||||
using System.Threading.Tasks; | 
					 | 
				
			||||||
using Hessian; | 
					 | 
				
			||||||
using DotXxlJob.Core.Config; | 
					 | 
				
			||||||
using DotXxlJob.Core.Model; | 
					 | 
				
			||||||
using Microsoft.Extensions.Logging; | 
					 | 
				
			||||||
using Microsoft.Extensions.Options; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace DotXxlJob.Core | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
     | 
					 | 
				
			||||||
    /// <summary> | 
					 | 
				
			||||||
    /// 负责执行Http请求,序列化和反序列化并发送响应 | 
					 | 
				
			||||||
    /// </summary> | 
					 | 
				
			||||||
    public class XxlRpcServiceHandler | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        | 
					 | 
				
			||||||
        private readonly JobDispatcher _jobDispatcher; | 
					 | 
				
			||||||
        private readonly IJobLogger _jobLogger; | 
					 | 
				
			||||||
        private readonly ILogger<XxlRpcServiceHandler> _logger; | 
					 | 
				
			||||||
        private readonly XxlJobExecutorOptions _options; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private readonly ConcurrentDictionary<string, MethodInfo> METHOD_CACHE = | 
					 | 
				
			||||||
            new ConcurrentDictionary<string, MethodInfo>();  | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
        public XxlRpcServiceHandler(IOptions<XxlJobExecutorOptions> optionsAccessor, | 
					 | 
				
			||||||
            JobDispatcher jobDispatcher,  | 
					 | 
				
			||||||
            IJobLogger jobLogger, | 
					 | 
				
			||||||
            ILogger<XxlRpcServiceHandler> logger) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            | 
					 | 
				
			||||||
            this._jobDispatcher = jobDispatcher; | 
					 | 
				
			||||||
            this._jobLogger = jobLogger; | 
					 | 
				
			||||||
            this._logger = logger; | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
            this._options = optionsAccessor.Value; | 
					 | 
				
			||||||
            if (this._options == null) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                throw  new ArgumentNullException(nameof(XxlJobExecutorOptions)); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        /// <summary> | 
					 | 
				
			||||||
        /// 处理XxlRpc请求流 | 
					 | 
				
			||||||
        /// </summary> | 
					 | 
				
			||||||
        /// <param name="reqStream"></param> | 
					 | 
				
			||||||
        /// <returns></returns> | 
					 | 
				
			||||||
        public async Task<byte[]> HandlerAsync(Stream reqStream) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var req = HessianSerializer.DeserializeRequest(reqStream); | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            var res = new RpcResponse { RequestId = req.RequestId}; | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            if (!ValidRequest(req, out var error)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._logger.LogWarning("job task request is not valid:{error}",error); | 
					 | 
				
			||||||
                res.ErrorMsg = error; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._logger.LogDebug("receive job task ,req.RequestId={requestId},method={methodName}" | 
					 | 
				
			||||||
                    ,req.RequestId,req.MethodName); | 
					 | 
				
			||||||
                await Invoke(req, res); | 
					 | 
				
			||||||
                this._logger.LogDebug("completed receive job task ,req.RequestId={requestId},method={methodName},IsError={IsError}" | 
					 | 
				
			||||||
                    ,req.RequestId,req.MethodName,res.IsError); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
           | 
					 | 
				
			||||||
            using (var outputStream = new MemoryStream()) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                HessianSerializer.SerializeResponse(outputStream,res); | 
					 | 
				
			||||||
                return outputStream.GetBuffer(); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary> | 
					 | 
				
			||||||
        /// 校验请求信息 | 
					 | 
				
			||||||
        /// </summary> | 
					 | 
				
			||||||
        /// <param name="req"></param> | 
					 | 
				
			||||||
        /// <param name="error"></param> | 
					 | 
				
			||||||
        /// <returns></returns> | 
					 | 
				
			||||||
        private bool ValidRequest(RpcRequest req,out string error) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            error = string.Empty; | 
					 | 
				
			||||||
            if (req == null) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                error = "unknown request stream data,codec fail"; | 
					 | 
				
			||||||
                return false; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            if (!"com.xxl.job.core.biz.ExecutorBiz".Equals(req.ClassName)) // | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                error =  "not supported request!"; | 
					 | 
				
			||||||
                return false; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
              | 
					 | 
				
			||||||
            if (DateTime.UtcNow.Subtract(req.CreateMillisTime.FromMilliseconds()) > Constants.RpcRequestExpireTimeSpan) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                error =  "request is timeout!"; | 
					 | 
				
			||||||
                return false; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (!string.IsNullOrEmpty(this._options.AccessToken) && this._options.AccessToken !=  req.AccessToken) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                error = "need authorize"; | 
					 | 
				
			||||||
                return false; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            return true; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary> | 
					 | 
				
			||||||
        /// 执行请求,获取执行函数 | 
					 | 
				
			||||||
        /// </summary> | 
					 | 
				
			||||||
        /// <param name="req"></param> | 
					 | 
				
			||||||
        /// <param name="res"></param> | 
					 | 
				
			||||||
        /// <returns></returns> | 
					 | 
				
			||||||
        private Task Invoke(RpcRequest req, RpcResponse res) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            try | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                var method = GetMethodInfo(req.MethodName); | 
					 | 
				
			||||||
                if (method == null) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    res.ErrorMsg = $"The method{req.MethodName} is not defined."; | 
					 | 
				
			||||||
                    this._logger.LogWarning( $"The method{req.MethodName} is not defined."); | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
                else | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    var result = method.Invoke(this, req.Parameters.ToArray()); | 
					 | 
				
			||||||
                     | 
					 | 
				
			||||||
                    res.Result = result; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
                | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            catch (Exception ex) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                res.ErrorMsg = ex.Message +"\n--------------\n"+ ex.StackTrace; | 
					 | 
				
			||||||
                this._logger.LogError(ex,"invoke method error:{0}",ex.Message); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return Task.CompletedTask; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private MethodInfo GetMethodInfo(string methodName) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (METHOD_CACHE.TryGetValue(methodName, out var method)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                return method; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            var type = GetType(); | 
					 | 
				
			||||||
            method = type.GetMethod( methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase); | 
					 | 
				
			||||||
            if (method != null) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                METHOD_CACHE.TryAdd(methodName, method); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return method; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        #region rpc service | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        private ReturnT Beat() | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            return ReturnT.SUCCESS; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private ReturnT IdleBeat(int jobId) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            return this._jobDispatcher.IdleBeat(jobId); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private ReturnT Kill(int jobId) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            return this._jobDispatcher.TryRemoveJobTask(jobId) ?  | 
					 | 
				
			||||||
                ReturnT.SUCCESS  | 
					 | 
				
			||||||
                :  | 
					 | 
				
			||||||
                ReturnT.Success("job thread already killed."); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary> | 
					 | 
				
			||||||
        ///  read Log | 
					 | 
				
			||||||
        /// </summary> | 
					 | 
				
			||||||
        /// <param name="logDateTime"></param> | 
					 | 
				
			||||||
        /// <param name="logId"></param> | 
					 | 
				
			||||||
        /// <param name="fromLineNum"></param> | 
					 | 
				
			||||||
        /// <returns></returns> | 
					 | 
				
			||||||
        private ReturnT Log(long logDateTime, int logId, int fromLineNum) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var ret =  ReturnT.Success(null); | 
					 | 
				
			||||||
            ret.Content = this._jobLogger.ReadLog(logDateTime, logId, fromLineNum); | 
					 | 
				
			||||||
            return ret; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary> | 
					 | 
				
			||||||
        /// 执行 | 
					 | 
				
			||||||
        /// </summary> | 
					 | 
				
			||||||
        /// <param name="triggerParam"></param> | 
					 | 
				
			||||||
        /// <returns></returns> | 
					 | 
				
			||||||
        private ReturnT Run(TriggerParam triggerParam) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
             return this._jobDispatcher.Execute(triggerParam); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
        #endregion | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,11 +0,0 @@ | 
				
			|||||||
using System.Collections.Generic; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Hessian | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public class ClassElement | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        public string ClassName { get; set; } | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        public List<PropertyElement> Fields { get; set; } | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
									
										
											File diff suppressed because it is too large
											Load Diff
										
									
								
							
						@ -1,39 +0,0 @@ | 
				
			|||||||
namespace Hessian | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    internal static class Marker | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        public const byte True = (byte) 'T';//0x54; | 
					 | 
				
			||||||
        public const byte False = (byte) 'F';// 0x46; | 
					 | 
				
			||||||
        public const byte Null = (byte) 'N';//0x4E; | 
					 | 
				
			||||||
        public const byte BinaryNonfinalChunk = (byte) 'b';//0x41; | 
					 | 
				
			||||||
        public const byte BinaryFinalChunk = (byte) 'B';//0x42; | 
					 | 
				
			||||||
        public const byte ClassDefinition = (byte) 'C';//0x43; | 
					 | 
				
			||||||
        public const byte DateTimeLong = 0x4A; | 
					 | 
				
			||||||
        public const byte DateTimeCompact = 0x4B; | 
					 | 
				
			||||||
        public const byte Double = 0x5A; | 
					 | 
				
			||||||
        public const byte DoubleZero = 0x5B; | 
					 | 
				
			||||||
        public const byte DoubleOne = 0x5C; | 
					 | 
				
			||||||
        public const byte DoubleOctet = 0x5D; | 
					 | 
				
			||||||
        public const byte DoubleShort = 0x5E; | 
					 | 
				
			||||||
        public const byte DoubleFloat = 0x5F; | 
					 | 
				
			||||||
        public const byte UnpackedInteger = (byte) 'I';// 0x49; | 
					 | 
				
			||||||
        public const byte PackedLong = (byte) 'Y';// 0x59; | 
					 | 
				
			||||||
        public const byte UnpackedLong = (byte) 'L';// 0x4C; | 
					 | 
				
			||||||
        public const byte StringNonfinalChunk = 0x52; | 
					 | 
				
			||||||
        public const byte StringFinalChunk = 0x53; | 
					 | 
				
			||||||
        public const byte VarList = 0x55; | 
					 | 
				
			||||||
        public const byte FixedList = 0x56; | 
					 | 
				
			||||||
        public const byte VarListUntyped = 0x57; | 
					 | 
				
			||||||
        public const byte FixListUntyped = 0x58; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public const byte CompactFixListStart = 0x70; | 
					 | 
				
			||||||
        public const byte CompactFixListEnd = 0x77; | 
					 | 
				
			||||||
        public const byte CompactFixListUntypedStart = 0x78; | 
					 | 
				
			||||||
        public const byte CompactFixListUntypedEnd = 0x7F; | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        public const byte ClassReference = (byte) 'O';//0x4F | 
					 | 
				
			||||||
        public const byte InstanceReference = (byte) 'Q'; //0x51; | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,142 +0,0 @@ | 
				
			|||||||
using System; | 
					 | 
				
			||||||
using System.IO; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Hessian | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public class PeekStream : Stream | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        private Stream inner; | 
					 | 
				
			||||||
        private byte? peek; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public PeekStream(Stream inner) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (inner == null) { | 
					 | 
				
			||||||
                throw new ArgumentNullException("inner"); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this.inner = inner; | 
					 | 
				
			||||||
            this.peek = null; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override bool CanRead { | 
					 | 
				
			||||||
            get { | 
					 | 
				
			||||||
                return inner.CanRead; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override bool CanSeek { | 
					 | 
				
			||||||
            get { | 
					 | 
				
			||||||
                return false; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override bool CanWrite { | 
					 | 
				
			||||||
            get { | 
					 | 
				
			||||||
                return false; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override long Length { | 
					 | 
				
			||||||
            get { | 
					 | 
				
			||||||
                return inner.Length; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override long Position { | 
					 | 
				
			||||||
            get { | 
					 | 
				
			||||||
                return inner.Position - (peek.HasValue ? 1 : 0); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            set { | 
					 | 
				
			||||||
                throw new NotSupportedException("Seeking not supported."); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public byte? Peek () | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (!peek.HasValue) { | 
					 | 
				
			||||||
                var b = inner.ReadByte(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (b == -1) { | 
					 | 
				
			||||||
                    return null; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                peek = (byte) b; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return peek; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override int ReadByte () | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (peek.HasValue) { | 
					 | 
				
			||||||
                var val = peek.Value; | 
					 | 
				
			||||||
                peek = null; | 
					 | 
				
			||||||
                return val; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return inner.ReadByte(); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override int Read (byte[] buffer, int offset, int count) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            Conditions.CheckNotNull(buffer, "buffer"); | 
					 | 
				
			||||||
            Conditions.CheckGreaterOrEqual(offset, 0, "offset"); | 
					 | 
				
			||||||
            Conditions.CheckLess(offset, buffer.Length, "offset"); | 
					 | 
				
			||||||
            Conditions.CheckGreaterOrEqual(count, 0, "count"); | 
					 | 
				
			||||||
            Conditions.CheckArgument( | 
					 | 
				
			||||||
                offset + count <= buffer.Length, | 
					 | 
				
			||||||
                "Buffer is not big enough to contain the requested amount of data at the given offset."); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (count == 0) { | 
					 | 
				
			||||||
                return 0; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var bytesToRead = count; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (peek.HasValue) { | 
					 | 
				
			||||||
                buffer[offset++] = peek.Value; | 
					 | 
				
			||||||
                peek = null; | 
					 | 
				
			||||||
                --bytesToRead; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            int bytesRead; | 
					 | 
				
			||||||
            while (bytesToRead > 0 && (bytesRead = inner.Read (buffer, offset, bytesToRead)) != 0) { | 
					 | 
				
			||||||
                offset += bytesRead; | 
					 | 
				
			||||||
                bytesToRead -= bytesRead; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return count - bytesToRead; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override void Write (byte[] buffer, int offset, int count) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            throw new NotSupportedException("Writes not supported."); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override void SetLength (long value) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            throw new NotSupportedException("Seeking not supported."); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override long Seek (long offset, SeekOrigin origin) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            throw new NotSupportedException("Seeking not supported."); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override void Flush () | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            throw new NotSupportedException("Writes not supported."); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override void Dispose (bool disposing) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (inner != null) { | 
					 | 
				
			||||||
                inner.Dispose (); | 
					 | 
				
			||||||
                inner = null; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            base.Dispose (disposing); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ -1,31 +0,0 @@ | 
				
			|||||||
using System; | 
					 | 
				
			||||||
using System.Collections.Generic; | 
					 | 
				
			||||||
using System.Reflection; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Hessian | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public class PropertyElement | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        public string Name { get; set; } | 
					 | 
				
			||||||
        public int Order { get; set; } | 
					 | 
				
			||||||
        public PropertyInfo PropertyInfo { get; set; } | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
     | 
					 | 
				
			||||||
    internal class PropertyComparer : IComparer<PropertyElement> | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        private readonly IComparer<int> comparer; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public PropertyComparer() | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            comparer = Comparer<int>.Default; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public int Compare(PropertyElement x, PropertyElement y) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var eq = comparer.Compare(x.Order, y.Order); | 
					 | 
				
			||||||
            return 0 == eq | 
					 | 
				
			||||||
                ? String.Compare(x.Name, y.Name, StringComparison.Ordinal) | 
					 | 
				
			||||||
                : eq; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,523 +0,0 @@ | 
				
			|||||||
using System; | 
					 | 
				
			||||||
using System.Collections; | 
					 | 
				
			||||||
using System.Collections.Concurrent; | 
					 | 
				
			||||||
using System.Collections.Generic; | 
					 | 
				
			||||||
using System.IO; | 
					 | 
				
			||||||
using System.Linq; | 
					 | 
				
			||||||
using System.Reflection; | 
					 | 
				
			||||||
using System.Runtime.Serialization; | 
					 | 
				
			||||||
using System.Text; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Hessian | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public class Serializer | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        static  readonly ConcurrentDictionary<Type,ClassElement> ClassDefCache =new ConcurrentDictionary<Type, ClassElement>(); | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        private readonly Stream _stream; | 
					 | 
				
			||||||
        private readonly HessianSerializationContext _context; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public Serializer (Stream stream) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            this._stream = stream ?? throw new ArgumentNullException(nameof(stream)); | 
					 | 
				
			||||||
            _context = new HessianSerializationContext(); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void WriteObject(object graph) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var objectType = graph.GetType(); | 
					 | 
				
			||||||
            if (!ClassDefCache.TryGetValue(objectType, out var classDef)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                classDef = GetClassDef(objectType.GetTypeInfo()); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
           | 
					 | 
				
			||||||
            var index = this._context.Instances.IndexOf(graph); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (index > -1) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteInstanceReference(index); | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this._context.Instances.Add(graph); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            index = this._context.Classes.IndexOf(objectType); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (index < 0) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                BeginClassDefinition(); | 
					 | 
				
			||||||
                WriteString(classDef.ClassName); | 
					 | 
				
			||||||
                WriteInt32(classDef.Fields.Count); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                foreach (var property in classDef.Fields) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    WriteString(property.Name); | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
                EndClassDefinition(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                index = this._context.Classes.Count; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                this._context.Classes.Add(objectType); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            WriteObjectReference(index); | 
					 | 
				
			||||||
            foreach (var item in classDef.Fields) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                var value = item.PropertyInfo.GetValue(graph); | 
					 | 
				
			||||||
                WriteValue(value); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void WriteValue(object val) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (val == null) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteNull(); | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            var valType = val.GetType(); | 
					 | 
				
			||||||
            var typeInfo = valType.GetTypeInfo(); | 
					 | 
				
			||||||
            if (IsSimpleType(typeInfo)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteSimpleValue(val); | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (IsListType(typeInfo)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteListValue(val); | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            WriteObject(val); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private void WriteListValue(object val) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var tag = (int)Marker.CompactFixListStart; | 
					 | 
				
			||||||
            if (!(val is ICollection eVal)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                throw new HessianException("write list data error"); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            tag += eVal.Count; | 
					 | 
				
			||||||
            if (tag > Marker.CompactFixListEnd) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                throw new HessianException("write list data error,tag too large"); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            this._stream.WriteByte((byte)tag); | 
					 | 
				
			||||||
            int index = 1; | 
					 | 
				
			||||||
            foreach (var item in eVal) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                if (index == 1) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    WriteString("["+GetItemTypeName(item.GetType())); | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
                WriteValue(item); | 
					 | 
				
			||||||
                index++; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private string GetItemTypeName(Type type) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var classType = type.GetCustomAttribute<DataContractAttribute>(); | 
					 | 
				
			||||||
            if (classType != null) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                return classType.Name; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (IsListType(type.GetTypeInfo())) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                return "java.util.List"; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return type.Name; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
        private void WriteSimpleValue(object val) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var valType = val.GetType(); | 
					 | 
				
			||||||
            if (valType == typeof(int)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteInt32((int)val); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else  if (valType == typeof(bool)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteBoolean((bool)val); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else  if (valType == typeof(long)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteInt64((long)val); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else  if (valType == typeof(double)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteDouble((double)val); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else  if (valType == typeof(string)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteString((string)val); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else  if (valType == typeof(DateTime)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteDateTime((DateTime)val); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        private ClassElement GetClassDef(TypeInfo typeInfo) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
           | 
					 | 
				
			||||||
           var classAttr = typeInfo.GetCustomAttribute<DataContractAttribute>(); | 
					 | 
				
			||||||
           if (classAttr == null) | 
					 | 
				
			||||||
           { | 
					 | 
				
			||||||
               throw  new HessianException("DataContract must be set"); | 
					 | 
				
			||||||
           } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
           ClassElement ce = new ClassElement {ClassName = classAttr.Name, Fields = new List<PropertyElement>()}; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
           //ClassDef def = new ClassDef(classAttr.Name); | 
					 | 
				
			||||||
           foreach (var property in typeInfo.DeclaredProperties) | 
					 | 
				
			||||||
           { | 
					 | 
				
			||||||
               var attribute = property.GetCustomAttribute<DataMemberAttribute>(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
               if (null == attribute) | 
					 | 
				
			||||||
               { | 
					 | 
				
			||||||
                   continue; | 
					 | 
				
			||||||
               } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
               if (!property.CanRead || !property.CanWrite) | 
					 | 
				
			||||||
               { | 
					 | 
				
			||||||
                   continue; | 
					 | 
				
			||||||
               } | 
					 | 
				
			||||||
               PropertyElement p = new PropertyElement { | 
					 | 
				
			||||||
                   Name = attribute.Name, | 
					 | 
				
			||||||
                   Order =  attribute.Order, | 
					 | 
				
			||||||
                   PropertyInfo = property | 
					 | 
				
			||||||
               }; | 
					 | 
				
			||||||
               ce.Fields .Add( p ); | 
					 | 
				
			||||||
           } | 
					 | 
				
			||||||
           ce.Fields.Sort(new PropertyComparer()); | 
					 | 
				
			||||||
           return ce; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary> | 
					 | 
				
			||||||
        /// Writes NULL token into stream | 
					 | 
				
			||||||
        /// </summary> | 
					 | 
				
			||||||
        public  void WriteNull() | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            this._stream.WriteByte(Marker.Null); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary> | 
					 | 
				
			||||||
        /// Writes <see cref="System.Boolean" /> value into output stream. | 
					 | 
				
			||||||
        /// </summary> | 
					 | 
				
			||||||
        /// <param name="value">The value.</param> | 
					 | 
				
			||||||
        public  void WriteBoolean(bool value) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            this._stream.WriteByte(value ? Marker.True : Marker.False); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary> | 
					 | 
				
			||||||
        /// Writes array of <see cref="System.Byte" /> into output stream. | 
					 | 
				
			||||||
        /// </summary> | 
					 | 
				
			||||||
        /// <param name="buffer">The value.</param> | 
					 | 
				
			||||||
        public void WriteBytes(byte[] buffer) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (null == buffer) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteNull(); | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            WriteBytes(buffer, 0, buffer.Length); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public  void WriteBytes(byte[] buffer, int offset, int count) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (offset < 0) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                throw new ArgumentException("", nameof(offset)); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (null == buffer) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                WriteNull(); | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (count < 0x10) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(0x20 + (count & 0x0F))); | 
					 | 
				
			||||||
                this._stream.Write(buffer, offset, count); | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            const int chunkSize = 0x8000; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            while (count > chunkSize) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte(Marker.BinaryNonfinalChunk); | 
					 | 
				
			||||||
                this._stream.WriteByte(chunkSize >> 8); | 
					 | 
				
			||||||
                this._stream.WriteByte(chunkSize & 0xFF); | 
					 | 
				
			||||||
                this._stream.Write(buffer, offset, chunkSize); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                count -= chunkSize; | 
					 | 
				
			||||||
                offset += chunkSize; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this._stream.WriteByte(Marker.BinaryFinalChunk); | 
					 | 
				
			||||||
            this._stream.WriteByte((byte)(count >> 8)); | 
					 | 
				
			||||||
            this._stream.WriteByte((byte)(count & 0xFF)); | 
					 | 
				
			||||||
            this._stream.Write(buffer, offset, count); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public  void WriteDateTime(DateTime value) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (value.Second == 0) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                var s = value.GetTotalMinutes(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                this._stream.WriteByte(Marker.DateTimeCompact); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(s >> 24)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(s >> 16)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(s >> 8)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)s); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var dt = value.GetTotalMilliseconds(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this._stream.WriteByte(Marker.DateTimeLong); | 
					 | 
				
			||||||
            this._stream.WriteByte((byte)(dt >> 56)); | 
					 | 
				
			||||||
            this._stream.WriteByte((byte)(dt >> 48)); | 
					 | 
				
			||||||
            this._stream.WriteByte((byte)(dt >> 40)); | 
					 | 
				
			||||||
            this._stream.WriteByte((byte)(dt >> 32)); | 
					 | 
				
			||||||
            this._stream.WriteByte((byte)(dt >> 24)); | 
					 | 
				
			||||||
            this._stream.WriteByte((byte)(dt >> 16)); | 
					 | 
				
			||||||
            this._stream.WriteByte((byte)(dt >> 8)); | 
					 | 
				
			||||||
            this._stream.WriteByte((byte)dt); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public  void WriteDouble(double value) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (value.Equals(0.0d)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte(Marker.DoubleZero); | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (value.Equals(1.0d)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte(Marker.DoubleOne); | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var fraction = Math.Abs(value - Math.Truncate(value)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (Double.Epsilon >= fraction) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                if (Byte.MinValue <= value && value <= Byte.MaxValue) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    this._stream.WriteByte(Marker.DoubleOctet); | 
					 | 
				
			||||||
                    this._stream.WriteByte(Convert.ToByte(value)); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    return; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (Int16.MinValue <= value && value <= Int16.MaxValue) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    var val = Convert.ToInt16(value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    this._stream.WriteByte(Marker.DoubleShort); | 
					 | 
				
			||||||
                    this._stream.WriteByte((byte)(val >> 8)); | 
					 | 
				
			||||||
                    this._stream.WriteByte((byte)val); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    return; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (Single.MinValue <= value && value <= Single.MaxValue) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                var bytes = BitConverter.GetBytes((float) value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                this._stream.WriteByte(Marker.DoubleFloat); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                for (var index = bytes.Length - 1; index >= 0; index--) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    this._stream.WriteByte(bytes[index]); | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var temp = BitConverter.DoubleToInt64Bits(value); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this._stream.WriteByte(Marker.Double); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for (var index = 56; index >= 0; index -= 8) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte((byte) (temp >> index)); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public  void WriteInt32(int value) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (-16 <= value && value < 48) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(0x90 + value)); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else if (-2048 <= value && value < 2048) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(0xC8 + (byte)(value >> 8))); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)value); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else if (-262144 <= value && value < 262144) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(0xD4 + (byte)(value >> 16))); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 8)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)value); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte(Marker.UnpackedInteger); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 24)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 16)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 8)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)value); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public  void WriteInt64(long value) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (-8 <= value && value < 16) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(0xE0 + value)); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else if (-2048 <= value && value < 2048) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(0xF8 + (byte)(value >> 8))); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)value); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else if (-262144 <= value && value < 262144) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(0x3C + (byte)(value >> 16))); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 8)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)value); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else if (Int32.MinValue <= value && value <= Int32.MaxValue) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte(Marker.PackedLong); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 24)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 16)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 8)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)value); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte(Marker.UnpackedLong); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 56)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 48)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 40)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 32)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 24)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 16)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(value >> 8)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)value); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public  void WriteString(string value) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (string.IsNullOrEmpty(value)) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte(0x00); | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var length = value.Length; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (1024 > length) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                var bytes = Encoding.UTF8.GetBytes(value.ToCharArray()); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (32 > length) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    this._stream.WriteByte((byte) length); | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
                else | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    this._stream.WriteByte((byte) (0x30 + (byte) (length >> 8))); | 
					 | 
				
			||||||
                    this._stream.WriteByte((byte) length); | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                this._stream.Write(bytes, 0, bytes.Length); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            const int maxChunkLength = 1024; | 
					 | 
				
			||||||
            var position = 0; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            while (position < length) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                var count = Math.Min(length - position, maxChunkLength); | 
					 | 
				
			||||||
                var final = length == (position + count); | 
					 | 
				
			||||||
                var chunk = value.Substring(position, count); | 
					 | 
				
			||||||
                var bytes = Encoding.UTF8.GetBytes(chunk.ToCharArray()); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                this._stream.WriteByte(final ? Marker.StringFinalChunk : Marker.StringNonfinalChunk); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(count >> 8)); | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)count); | 
					 | 
				
			||||||
                this._stream.Write(bytes, 0, bytes.Length); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                position += count; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
       | 
					 | 
				
			||||||
        public  void BeginClassDefinition() | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            this._stream.WriteByte(Marker.ClassDefinition); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public  void EndClassDefinition() | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public  void WriteObjectReference(int index) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (index < 0x10) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte((byte)(0x60 + index)); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            else | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                this._stream.WriteByte(Marker.ClassReference); | 
					 | 
				
			||||||
                WriteInt32(index); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public  void WriteInstanceReference(int index) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            this._stream.WriteByte(Marker.InstanceReference); | 
					 | 
				
			||||||
            WriteInt32(index); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        private static bool IsSimpleType(TypeInfo typeInfo) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (typeInfo.IsValueType || typeInfo.IsEnum || typeInfo.IsPrimitive) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                return true; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (typeof (String) == typeInfo.AsType()) | 
					 | 
				
			||||||
            { | 
					 | 
				
			||||||
                return true; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return false; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private static bool IsListType(TypeInfo typeInfo) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            return typeof(ICollection).IsAssignableFrom(typeInfo);           | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
@ -1,39 +0,0 @@ | 
				
			|||||||
using System; | 
					 | 
				
			||||||
using System.IO; | 
					 | 
				
			||||||
using System.Text; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Hessian | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public static class StringBuilderExtensions | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        public static StringBuilder AppendCodepoint(this StringBuilder sb, uint codepoint) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (codepoint < 0x10000) { | 
					 | 
				
			||||||
                return sb.Append((char)codepoint); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            var n = codepoint - 0x10000; | 
					 | 
				
			||||||
            var high = (char)((n >> 10) + 0xD800); | 
					 | 
				
			||||||
            var low  = (char)((n & 0x3FF) + 0xDC00); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            AssertValidSurrogates(high, low); | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            return sb | 
					 | 
				
			||||||
                .Append (high) | 
					 | 
				
			||||||
                .Append (low); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
         | 
					 | 
				
			||||||
        [System.Diagnostics.Conditional("DEBUG")] | 
					 | 
				
			||||||
        private static void AssertValidSurrogates (char high, char low) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            if (!Char.IsHighSurrogate (high)) { | 
					 | 
				
			||||||
                throw new InvalidDataException ("Invalid high surrogate"); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            if (!Char.IsLowSurrogate (low)) { | 
					 | 
				
			||||||
                throw new InvalidDataException ("Invalid low surrogate"); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ -1,163 +0,0 @@ | 
				
			|||||||
using System; | 
					 | 
				
			||||||
using System.IO; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Hessian | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public class ValueReader | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        private byte[] buffer = new byte[8]; | 
					 | 
				
			||||||
        private PeekStream stream; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public ValueReader (Stream stream) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            this.stream = stream as PeekStream ?? new PeekStream(stream); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public byte? Peek () | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            return stream.Peek (); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public short ReadShort () | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            Read (buffer, 0, 2); | 
					 | 
				
			||||||
            return BitConverter.ToInt16(buffer, 0); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public int ReadInt() | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            Read (buffer, 0, 4); | 
					 | 
				
			||||||
            return BitConverter.ToInt32(buffer, 0); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public uint ReadUtf8Codepoint () | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            const uint replacementChar = 0xFFFD; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            byte b0, b1, b2, b3; | 
					 | 
				
			||||||
            b0 = ReadByte (); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (b0 < 0x80) { | 
					 | 
				
			||||||
                return b0; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
  | 
					 | 
				
			||||||
            if (b0 < 0xC2) { | 
					 | 
				
			||||||
                return replacementChar; | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
            | 
					 | 
				
			||||||
            if (b0 < 0xE0) { | 
					 | 
				
			||||||
                b1 = ReadByte (); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if ((b1 ^ 0x80) >= 0x40) { | 
					 | 
				
			||||||
                    return replacementChar; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return (b1 & 0x3Fu) | ((b0 & 0x1Fu) << 6); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (b0 < 0xF0) { | 
					 | 
				
			||||||
                b1 = ReadByte (); | 
					 | 
				
			||||||
                b2 = ReadByte (); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Valid range: E0 A0..BF 80..BF | 
					 | 
				
			||||||
                if (b0 == 0xE0 && (b1 ^ 0xA0) >= 0x20) { | 
					 | 
				
			||||||
                    return replacementChar; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Valid range: ED 80..9F 80..BF | 
					 | 
				
			||||||
                if (b0 == 0xED && (b1 ^ 0x80) >= 0x20) { | 
					 | 
				
			||||||
                    return replacementChar; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Valid range: E1..EC 80..BF 80..BF | 
					 | 
				
			||||||
                if ((b1 ^ 0x80) >= 0x40 || (b2 ^ 0x80) >= 0x40) { | 
					 | 
				
			||||||
                    return replacementChar; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return (b2 & 0x3Fu) | 
					 | 
				
			||||||
                    | ((b1 & 0x3Fu) << 6) | 
					 | 
				
			||||||
                    | ((b0 & 0x0Fu) << 12); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (b0 < 0xF1) { | 
					 | 
				
			||||||
                b1 = ReadByte(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if ((b1 ^ 0x90) < 0x30) { | 
					 | 
				
			||||||
                    return replacementChar; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                b2 = ReadByte(); | 
					 | 
				
			||||||
                b3 = ReadByte(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) { | 
					 | 
				
			||||||
                    return replacementChar; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return (b3 & 0x3Fu) | 
					 | 
				
			||||||
                    | ((b2 & 0x3Fu) << 6) | 
					 | 
				
			||||||
                    | ((b1 & 0x3Fu) << 12) | 
					 | 
				
			||||||
                    | ((b0 & 0x07u) << 18); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            if (b0 < 0xF4) { | 
					 | 
				
			||||||
                b1 = ReadByte (); | 
					 | 
				
			||||||
                b2 = ReadByte (); | 
					 | 
				
			||||||
                b3 = ReadByte (); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Valid range: F1..F3 80..BF 80..BF 80..BF | 
					 | 
				
			||||||
                if ((b1 & 0xC0) != 0x80 || (b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    return replacementChar; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return (b3 & 0x3Fu) | 
					 | 
				
			||||||
                    | ((b2 & 0x3Fu) << 6) | 
					 | 
				
			||||||
                    | ((b1 & 0x3Fu) << 12) | 
					 | 
				
			||||||
                    | ((b0 & 0x07u) << 18); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (b0 < 0xF5) { | 
					 | 
				
			||||||
                b1 = ReadByte (); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Valid range: F4 80..8F 80..BF 80..BF | 
					 | 
				
			||||||
                if ((b1 ^ 0x80) >= 0x10) { | 
					 | 
				
			||||||
                    return replacementChar; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                b2 = ReadByte(); | 
					 | 
				
			||||||
                b3 = ReadByte(); | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) | 
					 | 
				
			||||||
                { | 
					 | 
				
			||||||
                    return replacementChar; | 
					 | 
				
			||||||
                } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return (b3 & 0x3Fu) | 
					 | 
				
			||||||
                    | ((b2 & 0x3Fu) << 6) | 
					 | 
				
			||||||
                    | ((b1 & 0x3Fu) << 12) | 
					 | 
				
			||||||
                    | ((b0 & 0x07u) << 18); | 
					 | 
				
			||||||
            } | 
					 | 
				
			||||||
             | 
					 | 
				
			||||||
            return replacementChar; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public byte ReadByte() | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var b = stream.ReadByte(); | 
					 | 
				
			||||||
            if (b == -1) throw new EndOfStreamException(); | 
					 | 
				
			||||||
            return (byte)b; | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void Read(byte[] buffer, int count) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            Read (buffer, 0, count); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private void Read(byte[] buffer, int offset, int count) | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
            var bytesRead = stream.Read (buffer, offset, count); | 
					 | 
				
			||||||
            if (bytesRead != count) throw new EndOfStreamException(); | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ -1,13 +0,0 @@ | 
				
			|||||||
using System; | 
					 | 
				
			||||||
using Xunit; | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Hessian.Tests | 
					 | 
				
			||||||
{ | 
					 | 
				
			||||||
    public class UnitTest1 | 
					 | 
				
			||||||
    { | 
					 | 
				
			||||||
        [Fact] | 
					 | 
				
			||||||
        public void Test1() | 
					 | 
				
			||||||
        { | 
					 | 
				
			||||||
        } | 
					 | 
				
			||||||
    } | 
					 | 
				
			||||||
} | 
					 | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue