├── .editorconfig ├── .github └── workflows │ ├── publish-beta.yml │ ├── publish.yml │ └── test.yml ├── .gitignore ├── App1 ├── App1.Android │ ├── App1.Android.csproj │ ├── Assets │ │ └── AboutAssets.txt │ ├── MainActivity.cs │ ├── Properties │ │ ├── AndroidManifest.xml │ │ └── AssemblyInfo.cs │ └── Resources │ │ ├── AboutResources.txt │ │ ├── Resource.designer.cs │ │ ├── drawable │ │ ├── icon_about.png │ │ ├── icon_feed.png │ │ └── xamarin_logo.png │ │ ├── mipmap-anydpi-v26 │ │ ├── icon.xml │ │ └── icon_round.xml │ │ ├── mipmap-hdpi │ │ ├── icon.png │ │ └── launcher_foreground.png │ │ ├── mipmap-mdpi │ │ ├── icon.png │ │ └── launcher_foreground.png │ │ ├── mipmap-xhdpi │ │ ├── icon.png │ │ └── launcher_foreground.png │ │ ├── mipmap-xxhdpi │ │ ├── icon.png │ │ └── launcher_foreground.png │ │ ├── mipmap-xxxhdpi │ │ ├── icon.png │ │ └── launcher_foreground.png │ │ └── values │ │ ├── colors.xml │ │ └── styles.xml └── App1 │ ├── App.xaml │ ├── App.xaml.cs │ ├── App1.csproj │ ├── AppShell.xaml │ ├── AppShell.xaml.cs │ ├── AssemblyInfo.cs │ ├── GettingStarted.txt │ ├── Models │ └── Item.cs │ ├── Services │ ├── IDataStore.cs │ └── MockDataStore.cs │ ├── ViewModels │ ├── AboutViewModel.cs │ ├── BaseViewModel.cs │ ├── ItemDetailViewModel.cs │ ├── ItemsViewModel.cs │ ├── LoginViewModel.cs │ └── NewItemViewModel.cs │ └── Views │ ├── AboutPage.xaml │ ├── AboutPage.xaml.cs │ ├── ItemDetailPage.xaml │ ├── ItemDetailPage.xaml.cs │ ├── ItemsPage.xaml │ ├── ItemsPage.xaml.cs │ ├── LoginPage.xaml │ ├── LoginPage.xaml.cs │ ├── NewItemPage.xaml │ └── NewItemPage.xaml.cs ├── Doc ├── Area.csv ├── WebSocket双向通信.pcapng ├── XCode.emmx ├── chunk分析.eddx ├── leaf.png ├── logo.ico ├── newlife.lua ├── newlife.pfx ├── newlife.snk ├── 插入字段逻辑.png └── 降采样 │ ├── LTOB降采样.png │ ├── LTOB降采样.xlsx │ ├── LTTB降采样.png │ └── LTTB降采样.xlsx ├── LICENSE ├── NewLife.Android └── NewLife.Android.csproj ├── NewLife.Core ├── Agent │ ├── AgentService.cs │ ├── AgentServiceBase.cs │ ├── ServiceHelper.cs │ └── Setting.cs ├── Algorithms │ ├── AlignModes.cs │ ├── AverageSampling.cs │ ├── BilinearInterpolation.cs │ ├── BucketModes.cs │ ├── BucketSource.cs │ ├── IInterpolation.cs │ ├── ISampling.cs │ ├── LTOBSampling.cs │ ├── LTTBSampling.cs │ ├── LagrangeInterpolation.cs │ ├── LinearInterpolation.cs │ ├── MaxSampling.cs │ ├── MinSampling.cs │ └── SumSampling.cs ├── Applications │ └── IP │ │ ├── Ip.cs │ │ └── Zip.cs ├── Buffers │ ├── BufferSegment.cs │ ├── PooledByteBufferWriter.cs │ ├── SpanHelper.cs │ ├── SpanReader.cs │ └── SpanWriter.cs ├── Caching │ ├── Cache.cs │ ├── CacheLock.cs │ ├── CacheProvider.cs │ ├── ICache.cs │ ├── ICacheProvider.cs │ ├── IProducerConsumer.cs │ ├── MemoryCache.cs │ ├── QueueEventBus.cs │ ├── Readme.MD │ ├── Redis.cs │ ├── RedisClient.cs │ └── RedisEncoder.cs ├── Collections │ ├── BloomFilter.cs │ ├── CollectionHelper.cs │ ├── ConcurrentHashSet.cs │ ├── DictionaryCache.cs │ ├── IArrayPool.cs │ ├── ICluster.cs │ ├── IDictionarySource.cs │ ├── IPool.cs │ ├── NullableDictionary.cs │ ├── ObjectPool.cs │ ├── Pool.cs │ └── QueueService.cs ├── Common │ ├── DisposeBase.cs │ ├── Gen2GcCallback.cs │ ├── Index.cs │ ├── MachineInfo.cs │ ├── PinYin.cs │ ├── Range.cs │ ├── Runtime.cs │ ├── SysConfig.cs │ ├── TimeProvider.cs │ └── Utility.cs ├── Compression │ ├── SevenZip.cs │ └── TarFile.cs ├── Configuration │ ├── ApolloConfigProvider.cs │ ├── CommandParser.cs │ ├── CompositeConfigProvider.cs │ ├── Config.cs │ ├── ConfigAttribute.cs │ ├── ConfigCacheLevel.cs │ ├── ConfigHelper.cs │ ├── FileConfigProvider.cs │ ├── GetConfigCallback.cs │ ├── HttpConfigProvider.cs │ ├── IConfigMapping.cs │ ├── IConfigProvider.cs │ ├── IConfigSection.cs │ ├── IniConfigProvider.cs │ ├── JsonConfigProvider.cs │ └── XmlConfigProvider.cs ├── Data │ ├── BinaryTree.cs │ ├── DbRow.cs │ ├── DbTable.cs │ ├── GeoAddress.cs │ ├── GeoArea.cs │ ├── GeoHash.cs │ ├── GeoPoint.cs │ ├── IData.cs │ ├── IExtend.cs │ ├── IFilter.cs │ ├── IMemoryEncoder.cs │ ├── IModel.cs │ ├── IPacket.cs │ ├── IPacketEncoder.cs │ ├── IndexRange.cs │ ├── Packet.cs │ ├── PageParameter.cs │ ├── RingBuffer.cs │ ├── Snowflake.cs │ └── TimePoint.cs ├── Event │ ├── EventArgs.cs │ └── WeakAction.cs ├── Exceptions │ └── XException.cs ├── Expressions │ ├── IndexInfo.cs │ ├── MathExpression.cs │ ├── RpnExpression.cs │ └── UnionExpresion.cs ├── Extension │ ├── BitHelper.cs │ ├── ConcurrentDictionaryExtensions.cs │ ├── EndPointExtensions.cs │ ├── EnumHelper.cs │ ├── ListExtension.cs │ ├── ProcessHelper.cs │ ├── SpeakProvider.cs │ └── StringHelper.cs ├── Http │ ├── ControllerHandler.cs │ ├── DefaultHttpClientFactory.cs │ ├── DnsHttpHandler.cs │ ├── FormFile.cs │ ├── HttpBase.cs │ ├── HttpClient.cs │ ├── HttpCodec.cs │ ├── HttpEncoder.cs │ ├── HttpHelper.cs │ ├── HttpRequest.cs │ ├── HttpResponse.cs │ ├── HttpServer.cs │ ├── HttpSession.cs │ ├── HttpTraceHandler.cs │ ├── IHttpClientFactory.cs │ ├── IHttpContext.cs │ ├── IHttpFilter.cs │ ├── IHttpHandler.cs │ ├── IHttpHost.cs │ ├── StaticFilesHandler.cs │ ├── TinyHttpClient.cs │ ├── TokenHttpFilter.cs │ ├── WebSocket.cs │ ├── WebSocketHandler.cs │ └── WebSocketMessage.cs ├── IO │ ├── CsvDb.cs │ ├── CsvFile.cs │ ├── EasyClient.cs │ ├── EncodingHelper.cs │ ├── ExcelReader.cs │ ├── FileSource.cs │ ├── IOHelper.cs │ ├── IObjectInfo.cs │ ├── IObjectStorage.cs │ └── PathHelper.cs ├── Json │ ├── JsonConfig.cs │ └── JsonConfigFileAttribute.cs ├── Log │ ├── ActionLog.cs │ ├── CodeTimer.cs │ ├── CompositeLog.cs │ ├── ConsoleLog.cs │ ├── ICounter.cs │ ├── ILog.cs │ ├── ILogFeature.cs │ ├── ISpan.cs │ ├── ISpanBuilder.cs │ ├── ITracer.cs │ ├── ITracerFeature.cs │ ├── ITracerResolver.cs │ ├── LevelLog.cs │ ├── LogEventListener.cs │ ├── LogLevel.cs │ ├── Logger.cs │ ├── NetworkLog.cs │ ├── PerfCounter.cs │ ├── Readme.md │ ├── TextControlLog.cs │ ├── TextFileLog.cs │ ├── TimeCost.cs │ ├── TraceStream.cs │ ├── WriteLogEventArgs.cs │ └── XTrace.cs ├── Messaging │ ├── DefaultMessage.cs │ ├── IEventBus.cs │ ├── IMessage.cs │ ├── MessageEventArgs.cs │ └── PacketCodec.cs ├── Model │ ├── Actor.cs │ ├── DeferredQueue.cs │ ├── Host.cs │ ├── IAuthUser.cs │ ├── IFactory.cs │ ├── IHandler.cs │ ├── IHandlerContext.cs │ ├── IManageUser.cs │ ├── IObjectContainer.cs │ ├── IPipeline.cs │ ├── IPlugin.cs │ ├── IServer.cs │ ├── IServiceScope.cs │ ├── IServiceScopeFactory.cs │ ├── ModelExtension.cs │ ├── ObjectContainer.cs │ └── ObjectContainerHelper.cs ├── Net │ ├── Handlers │ │ ├── IMatchQueue.cs │ │ ├── JsonCodec.cs │ │ ├── LengthFieldCodec.cs │ │ ├── MessageCodec.cs │ │ ├── SplitDataCodec.cs │ │ ├── StandardCodec.cs │ │ └── WebSocketCodec.cs │ ├── IDnsResolver.cs │ ├── IIPResolver.cs │ ├── INetHandler.cs │ ├── INetSession.cs │ ├── ISocket.cs │ ├── ISocketClient.cs │ ├── ISocketRemote.cs │ ├── ISocketServer.cs │ ├── ISocketSession.cs │ ├── ITransport.cs │ ├── NetException.cs │ ├── NetHandlerContext.cs │ ├── NetHelper.cs │ ├── NetServer.cs │ ├── NetSession.cs │ ├── NetUri.cs │ ├── Readme.md │ ├── ReceivedEventArgs.cs │ ├── SerialPortConfig.cs │ ├── SerialTransport.cs │ ├── SessionBase.cs │ ├── SessionCollection.cs │ ├── Setting.cs │ ├── SocketHelper.cs │ ├── TcpConnectionInformation2.cs │ ├── TcpServer.cs │ ├── TcpSession.cs │ ├── UdpServer.cs │ ├── UdpSession.cs │ ├── Upgrade.cs │ ├── WebSocketClient.cs │ └── WebSocketSession.cs ├── NewLife.Core.csproj ├── Properties │ ├── AssemblyInfo.cs │ └── PublishProfiles │ │ └── FolderProfile.pubxml ├── Reflection │ ├── AssemblyX.cs │ ├── AttributeX.cs │ ├── DynamicInternal.cs │ ├── DynamicXml.cs │ ├── IIndexAccessor.cs │ ├── IReflect.cs │ ├── OrcasNamer.cs │ ├── Reflect.cs │ └── ScriptEngine.cs ├── Remoting │ ├── ApiAction.cs │ ├── ApiAttribute.cs │ ├── ApiClient.cd │ ├── ApiClient.cs │ ├── ApiCode.cs │ ├── ApiException.cs │ ├── ApiHelper.cs │ ├── ApiHost.cs │ ├── ApiHttpClient.cs │ ├── ApiHttpServer.cs │ ├── ApiNetServer.cs │ ├── ApiServer.cd │ ├── ApiServer.cs │ ├── ClientPoolCluster.cs │ ├── ClientSingleCluster.cs │ ├── Controllers │ │ └── ApiController.cs │ ├── Filters │ │ ├── ControllerContext.cs │ │ └── IActionFilter.cs │ ├── HttpClientEventArgs.cs │ ├── HttpRequestEventArgs.cs │ ├── IApi.cs │ ├── IApiClient.cs │ ├── IApiHandler.cs │ ├── IApiHost.cs │ ├── IApiManager.cs │ ├── IApiServer.cs │ ├── IApiSession.cs │ ├── IEncoder.cs │ └── JsonEncoder.cs ├── Security │ ├── AlgorithmKeyBlob.cs │ ├── Asn1.cs │ ├── Asn1Tags.cs │ ├── CbcTransform.cs │ ├── Certificate.cs │ ├── Crc16.cs │ ├── Crc32.cs │ ├── DSAHelper.cs │ ├── ECDsaHelper.cs │ ├── ECKey.cs │ ├── IPasswordProvider.cs │ ├── Murmur128.cs │ ├── PKCS7PaddingTransform.cs │ ├── ProtectedKey.cs │ ├── RC4.cs │ ├── RSAHelper.cs │ ├── Rand.cs │ ├── SM4.cs │ ├── SecurityHelper.cs │ └── ZerosPaddingTransform.cs ├── Serialization │ ├── Accessor.cs │ ├── Binary │ │ ├── Binary.cs │ │ ├── BinaryColor.cs │ │ ├── BinaryComposite.cs │ │ ├── BinaryDictionary.cs │ │ ├── BinaryFont.cs │ │ ├── BinaryGeneral.cs │ │ ├── BinaryList.cs │ │ ├── BinaryNormal.cs │ │ ├── BinaryPair.cs │ │ ├── BinaryUnknown.cs │ │ ├── FieldSizeAttribute.cs │ │ └── IBinary.cs │ ├── BinaryCodec.cs │ ├── BinaryCodec2.cs │ ├── DataMemberResolver.cs │ ├── ExtendableConverter.cs │ ├── Interface │ │ ├── AccessorAttribute.cs │ │ ├── AccessorContext.cs │ │ ├── FixedStringAttribute.cs │ │ ├── FullStringAttribute.cs │ │ ├── IAccessor.cs │ │ ├── IFormatterX.cs │ │ └── IMemberAccessor.cs │ ├── Json │ │ ├── IJson.cs │ │ ├── IJsonHost.cs │ │ ├── Json.cs │ │ ├── JsonArray.cs │ │ ├── JsonComposite.cs │ │ ├── JsonDictionary.cs │ │ ├── JsonGeneral.cs │ │ ├── JsonOptions.cs │ │ ├── JsonParser.cs │ │ ├── JsonReader.cs │ │ ├── JsonTest.cs │ │ └── JsonWriter.cs │ ├── JsonCodec.cs │ ├── JsonCodec2.cs │ ├── JsonConverter.cs │ ├── LocalTimeConverter.cs │ ├── SerialHelper.cs │ ├── ServiceTypeResolver.cs │ ├── TypeConverter.cs │ └── Xml │ │ ├── IXml.cs │ │ ├── Xml.cs │ │ ├── XmlComposite.cs │ │ ├── XmlGeneral.cs │ │ ├── XmlList.cs │ │ └── XmlParser.cs ├── Setting.cs ├── Stub │ ├── IsExternalInit.cs │ ├── MaybeNullAttribute.cs │ ├── MaybeNullWhenAttribute.cs │ ├── MemberNotNullAttribute.cs │ ├── MemberNotNullWhenAttribute.cs │ ├── NotNullAttribute.cs │ ├── NotNullIfNotNullAttribute.cs │ ├── NotNullWhenAttribute.cs │ └── ScriptIgnoreAttribute.cs ├── Threading │ ├── Cron.cs │ ├── ITimer.cs │ ├── TaskEx.cs │ ├── ThreadPoolX.cs │ ├── TimerScheduler.cs │ └── TimerX.cs ├── UpdateInfo.txt ├── Web │ ├── JwtBuilder.cs │ ├── Link.cs │ ├── OAuth │ │ ├── BaiduClient.cs │ │ ├── GithubClient.cs │ │ ├── QQClient.cs │ │ ├── TaobaoClient.cs │ │ └── WeixinClient.cs │ ├── OAuthClient.cs │ ├── OAuthConfig.cs │ ├── OAuthServer.cs │ ├── Pager.cs │ ├── PluginHelper.cs │ ├── TokenModel.cs │ ├── TokenProvider.cs │ ├── UriInfo.cs │ ├── WebClientX.cs │ └── WebHelper.cs ├── Windows │ ├── ConsoleHelper.cs │ ├── ControlHelper.cs │ ├── MySpeech.cs │ ├── PowerStatus.cs │ └── SpeechRecognition.cs ├── Xml │ ├── SerializableDictionary.cs │ ├── XmlConfig.cs │ ├── XmlConfigFileAttribute.cs │ └── XmlHelper.cs ├── X组件.txt ├── Yun │ ├── AMap.cs │ ├── BaiduMap.cs │ ├── Driving.cs │ ├── Map.cs │ ├── OssClient.cs │ └── WeMap.cs └── 说明.txt ├── NewLife.Security └── NewLife.Security.csproj ├── Readme.MD ├── Samples ├── MobileApp │ ├── MobileApp.Android │ │ ├── Assets │ │ │ └── AboutAssets.txt │ │ ├── MainActivity.cs │ │ ├── MobileApp.Android.csproj │ │ ├── Properties │ │ │ ├── AndroidManifest.xml │ │ │ └── AssemblyInfo.cs │ │ └── Resources │ │ │ ├── AboutResources.txt │ │ │ ├── Resource.designer.cs │ │ │ ├── drawable │ │ │ └── xamarin_logo.png │ │ │ ├── layout │ │ │ ├── Tabbar.xml │ │ │ └── Toolbar.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── icon.xml │ │ │ └── icon_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── icon.png │ │ │ └── launcher_foreground.png │ │ │ ├── mipmap-mdpi │ │ │ ├── icon.png │ │ │ └── launcher_foreground.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── icon.png │ │ │ └── launcher_foreground.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── icon.png │ │ │ └── launcher_foreground.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── icon.png │ │ │ └── launcher_foreground.png │ │ │ └── values │ │ │ ├── colors.xml │ │ │ └── styles.xml │ ├── MobileApp.iOS │ │ ├── AppDelegate.cs │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon1024.png │ │ │ │ ├── Icon120.png │ │ │ │ ├── Icon152.png │ │ │ │ ├── Icon167.png │ │ │ │ ├── Icon180.png │ │ │ │ ├── Icon20.png │ │ │ │ ├── Icon29.png │ │ │ │ ├── Icon40.png │ │ │ │ ├── Icon58.png │ │ │ │ ├── Icon60.png │ │ │ │ ├── Icon76.png │ │ │ │ ├── Icon80.png │ │ │ │ └── Icon87.png │ │ ├── Entitlements.plist │ │ ├── Info.plist │ │ ├── Main.cs │ │ ├── MobileApp.iOS.csproj │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ └── Resources │ │ │ ├── Default-568h@2x.png │ │ │ ├── Default-Portrait.png │ │ │ ├── Default-Portrait@2x.png │ │ │ ├── Default.png │ │ │ ├── Default@2x.png │ │ │ ├── LaunchScreen.storyboard │ │ │ ├── tab_about.png │ │ │ ├── tab_about@2x.png │ │ │ ├── tab_about@3x.png │ │ │ ├── tab_feed.png │ │ │ ├── tab_feed@2x.png │ │ │ ├── tab_feed@3x.png │ │ │ ├── xamarin_logo.png │ │ │ ├── xamarin_logo@2x.png │ │ │ └── xamarin_logo@3x.png │ └── MobileApp │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── AssemblyInfo.cs │ │ ├── MobileApp.csproj │ │ ├── Models │ │ ├── HomeMenuItem.cs │ │ └── Item.cs │ │ ├── Services │ │ ├── IDataStore.cs │ │ └── MockDataStore.cs │ │ ├── ViewModels │ │ ├── AboutViewModel.cs │ │ ├── BaseViewModel.cs │ │ ├── ItemDetailViewModel.cs │ │ └── ItemsViewModel.cs │ │ └── Views │ │ ├── AboutPage.xaml │ │ ├── AboutPage.xaml.cs │ │ ├── ItemDetailPage.xaml │ │ ├── ItemDetailPage.xaml.cs │ │ ├── ItemsPage.xaml │ │ ├── ItemsPage.xaml.cs │ │ ├── MainPage.xaml │ │ ├── MainPage.xaml.cs │ │ ├── MenuPage.xaml │ │ ├── MenuPage.xaml.cs │ │ ├── NewItemPage.xaml │ │ └── NewItemPage.xaml.cs ├── Zero.Desktop │ ├── ClientSetting.cs │ ├── FrmMain.Designer.cs │ ├── FrmMain.cs │ ├── FrmMain.resx │ ├── Program.cs │ ├── Zero.Desktop.csproj │ ├── app.manifest │ └── appsettings.json ├── Zero.EchoServer │ ├── EchoNetServer.cs │ ├── Program.cs │ ├── Zero.EchoServer.csproj │ └── appsettings.json ├── Zero.HttpServer │ ├── ClientTest.cs │ ├── MyHttpHandler.cs │ ├── MyWebSocketHandler.cs │ ├── Program.cs │ ├── Zero.HttpServer.csproj │ └── appsettings.json └── Zero.Server │ ├── ClientTest.cs │ ├── Handlers │ ├── IMsgHandler.cs │ └── MyHandler.cs │ ├── MyNetServer.cs │ ├── Program.cs │ ├── Zero.Server.csproj │ └── appsettings.json ├── Test ├── App.config ├── BigInteger.cs ├── ConfigTest.cs ├── Program.cs ├── Properties │ ├── PublishProfiles │ │ └── FolderProfile.pubxml │ └── launchSettings.json ├── Test.csproj ├── app.manifest ├── appsettings.json └── form.html ├── Test2 ├── App.config ├── Program.cs └── Test2.csproj ├── XUnitTest.Core ├── Algorithms │ ├── AverageDownSamplingTests.cs │ ├── LTOBDownSamplingTests.cs │ ├── LttbDownSamplingTests.cs │ ├── SamplingTests.cs │ ├── sampled.csv │ ├── source.csv │ └── source2.csv ├── Applications │ └── IpTests.cs ├── Buffers │ ├── SpanHelperTests.cs │ ├── SpanReaderTests.cs │ └── SpanWriterTests.cs ├── Caching │ ├── MemoryCacheTests.cs │ ├── MemoryQueueTests.cs │ └── RedisTest.cs ├── Collections │ ├── BloomFilterTests.cs │ └── CollectionHelperTests.cs ├── Common │ ├── LockTests.cs │ ├── MachineInfoTests.cs │ ├── PinYinTests.cs │ ├── SysConfigTest.cs │ └── UtilityTests.cs ├── Compression │ ├── TarEntryTests.cs │ └── TarFileTests.cs ├── Configuration │ ├── CommandParserTests.cs │ ├── CompositeConfigProviderTests.cs │ ├── ConfigModel.cs │ ├── ConfigProviderTests.cs │ ├── HttpConfigProviderTests.cs │ ├── IniConfigProviderTests.cs │ ├── JsonConfigProviderTests.cs │ ├── OAuthConfig.cs │ └── XmlConfigProviderTests.cs ├── Data │ ├── ArrayPacketTests.cs │ ├── DbTableTests.cs │ ├── FlowIdTests.cs │ ├── GeoHashTests.cs │ ├── IExtendTests.cs │ ├── IPacketTests.cs │ ├── PacketTests.cs │ └── RingBufferTests.cs ├── Expressions │ ├── BinaryTreeTests.cs │ └── MathTests.cs ├── Extension │ ├── ProcessHelperTests.cs │ └── StringHelperTests.cs ├── GeoArea.cs ├── Http │ ├── HttpCodecTests.cs │ ├── HttpHelperTests.cs │ ├── HttpServerTests.cs │ ├── TinyHttpClientTest.cs │ ├── WebSocketMessageTests.cs │ └── leaf.png ├── IO │ ├── CsvDbTests.cs │ ├── CsvFileTests.cs │ ├── EasyClientTests.cs │ ├── ExcelReaderTests.cs │ ├── IOHelperTests.cs │ ├── PathHelperTests.cs │ └── excel.xlsx ├── Json │ └── JsonConfigTest.cs ├── Log │ ├── LevelLogTests.cs │ ├── NetworkLogTests.cs │ ├── PerfCounterTests.cs │ └── TracerTests.cs ├── Messaging │ ├── DefaultMessageTests.cs │ └── EventBusTests.cs ├── Model │ ├── ActorTests.cs │ ├── HostTests.cs │ ├── ObjectContainerTests.cs │ └── PipelineTests.cs ├── Net │ ├── ISocketRemoteTests.cs │ ├── NetSeverTests.cs │ ├── NetUriTests.cs │ ├── TcpConnectionInformation2Tests.cs │ ├── TcpSessionTests.cs │ └── UpgradeTests.cs ├── PacketTest.cs ├── PageParameterTest.cs ├── PropertyInfo.cs ├── Reflection │ ├── AssemblyXTests.cs │ └── ReflectTests.cs ├── Remoting │ ├── ApiDownTests.cs │ ├── ApiHelperTest.cs │ ├── ApiHttpClientTests.cs │ └── ApiTest.cs ├── Security │ ├── Crc16Tests.cs │ ├── Crc32Tests.cs │ ├── ECDsaHelperTests.cs │ ├── KeyBlobMagicNumber.cs │ ├── PasswordProviderTests.cs │ ├── ProtectedKeyTests.cs │ ├── RSAHelperTests.cs │ ├── RandTests.cs │ ├── SM4Tests.cs │ └── SecurityHelperTests.cs ├── Serialization │ ├── BinaryTests.cs │ ├── FDLibBaseCfg.cs │ ├── FastJsonTest.cs │ ├── JsonParserTests.cs │ ├── JsonTest.cs │ ├── JsonTestBase.cs │ ├── JsonWriterTests.cs │ ├── SerialHelperTests.cs │ ├── StarAgent.config │ ├── StarSetting.cs │ ├── SystemJsonTest.cs │ └── XmlTest.cs ├── TestEntity │ ├── 历史.Biz.cs │ └── 历史.cs ├── Threading │ ├── CronTests.cs │ └── TimerXTests.cs ├── Web │ ├── JwtBuilderTests.cs │ ├── LinkTests.cs │ ├── TokenProviderTests.cs │ ├── UriInfoTests.cs │ └── WebClientTests.cs ├── XUnitTest.Core.csproj ├── Yun │ ├── BaiduMapTests.cs │ └── OssClientTests.cs └── appsettings.json ├── X组件.sln └── global.json /.github/workflows/publish-beta.yml: -------------------------------------------------------------------------------- 1 | name: publish-beta 2 | 3 | on: 4 | push: 5 | branches: [ dev ] 6 | paths: 7 | - 'NewLife.Core/**' 8 | pull_request: 9 | branches: [ dev ] 10 | paths: 11 | - 'NewLife.Core/**' 12 | workflow_dispatch: 13 | 14 | jobs: 15 | build-publish: 16 | runs-on: windows-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Setup dotNET 21 | uses: actions/setup-dotnet@v4 22 | with: 23 | dotnet-version: | 24 | 6.x 25 | 7.x 26 | 8.x 27 | 9.x 28 | - name: Get Version 29 | run: echo "VERSION=$(date '+%Y.%m%d-beta%H%M')" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append 30 | - name: Build 31 | run: | 32 | dotnet pack --version-suffix ${{ env.VERSION }} -c Release -o out NewLife.Core\NewLife.Core.csproj 33 | - name: Publish 34 | run: | 35 | dotnet nuget push .\out\*.nupkg --skip-duplicate --source https://nuget.pkg.github.com/NewLifeX/index.json --api-key ${{ github.token }} 36 | dotnet nuget push .\out\*.nupkg --skip-duplicate --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.nugetKey }} 37 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | 3 | on: 4 | push: 5 | tags: [ v* ] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build-publish: 10 | runs-on: windows-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Setup dotNET 15 | uses: actions/setup-dotnet@v4 16 | with: 17 | dotnet-version: | 18 | 6.x 19 | 7.x 20 | 8.x 21 | 9.x 22 | - name: Get Version 23 | run: echo "VERSION=$(date '+%Y.%m%d')" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append 24 | - name: Build 25 | run: | 26 | dotnet pack --version-suffix ${{ env.VERSION }} -c Release -o out NewLife.Core\NewLife.Core.csproj 27 | dotnet pack --version-suffix ${{ env.VERSION }} -c Release -o out NewLife.Security\NewLife.Security.csproj 28 | - name: Publish 29 | run: | 30 | dotnet nuget push .\out\*.nupkg --skip-duplicate --source https://nuget.pkg.github.com/NewLifeX/index.json --api-key ${{ github.token }} 31 | dotnet nuget push .\out\*.nupkg --skip-duplicate --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.nugetKey }} 32 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: [ '*' ] 6 | pull_request: 7 | branches: [ '*' ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | test: 12 | runs-on: windows-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Setup dotNET 17 | uses: actions/setup-dotnet@v4 18 | with: 19 | dotnet-version: | 20 | 6.x 21 | 7.x 22 | 8.x 23 | 9.x 24 | - name: Build 25 | run: | 26 | dotnet build -c Release 27 | - name: Test 28 | run: | 29 | dotnet test -f net8.0 30 | dotnet test -f net9.0 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。 3 | ################################################################################ 4 | 5 | /.vs 6 | [Dd]ebug/ 7 | [Dd]ebugPublic/ 8 | [Rr]elease/ 9 | [Rr]eleases/ 10 | x64/ 11 | x86/ 12 | build/ 13 | bld/ 14 | [Bb]in/ 15 | [Oo]bj/ 16 | /packages 17 | *.user 18 | /Data 19 | /Log 20 | *.log 21 | *.htm 22 | *.nuspec 23 | *.nupkg 24 | [Cc]onfig/ 25 | [Ll]og/ -------------------------------------------------------------------------------- /App1/App1.Android/Assets/AboutAssets.txt: -------------------------------------------------------------------------------- 1 | Any raw assets you want to be deployed with your application can be placed in 2 | this directory (and child directories) and given a Build Action of "AndroidAsset". 3 | 4 | These files will be deployed with your package and will be accessible using Android's 5 | AssetManager, like this: 6 | 7 | public class ReadAsset : Activity 8 | { 9 | protected override void OnCreate (Bundle bundle) 10 | { 11 | base.OnCreate (bundle); 12 | 13 | InputStream input = Assets.Open ("my_asset.txt"); 14 | } 15 | } 16 | 17 | Additionally, some Android functions will automatically load asset files: 18 | 19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); 20 | -------------------------------------------------------------------------------- /App1/App1.Android/MainActivity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using Android.App; 4 | using Android.Content.PM; 5 | using Android.Runtime; 6 | using Android.OS; 7 | 8 | namespace App1.Droid 9 | { 10 | [Activity(Label = "App1", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )] 11 | public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity 12 | { 13 | protected override void OnCreate(Bundle savedInstanceState) 14 | { 15 | base.OnCreate(savedInstanceState); 16 | 17 | Xamarin.Essentials.Platform.Init(this, savedInstanceState); 18 | global::Xamarin.Forms.Forms.Init(this, savedInstanceState); 19 | LoadApplication(new App()); 20 | } 21 | public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults) 22 | { 23 | Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults); 24 | 25 | base.OnRequestPermissionsResult(requestCode, permissions, grantResults); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /App1/App1.Android/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /App1/App1.Android/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using Android.App; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("App1.Android")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("App1.Android")] 14 | [assembly: AssemblyCopyright("Copyright © 2014")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: ComVisible(false)] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | [assembly: AssemblyVersion("1.0.0.0")] 26 | [assembly: AssemblyFileVersion("1.0.0.0")] 27 | 28 | // Add some common permissions, these can be removed if not needed 29 | [assembly: UsesPermission(Android.Manifest.Permission.Internet)] 30 | [assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)] 31 | -------------------------------------------------------------------------------- /App1/App1.Android/Resources/drawable/icon_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/drawable/icon_about.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/drawable/icon_feed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/drawable/icon_feed.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/drawable/xamarin_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/drawable/xamarin_logo.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-anydpi-v26/icon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-anydpi-v26/icon_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/mipmap-hdpi/icon.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-hdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/mipmap-hdpi/launcher_foreground.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/mipmap-mdpi/icon.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-mdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/mipmap-mdpi/launcher_foreground.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/mipmap-xhdpi/icon.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-xhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/mipmap-xhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/mipmap-xxhdpi/icon.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-xxhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/mipmap-xxhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/mipmap-xxxhdpi/icon.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/App1/App1.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /App1/App1.Android/Resources/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | #3F51B5 5 | #303F9F 6 | #FF4081 7 | 8 | -------------------------------------------------------------------------------- /App1/App1.Android/Resources/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | -------------------------------------------------------------------------------- /App1/App1/App.xaml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 8 | 9 | 10 | #2196F3 11 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /App1/App1/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using App1.Services; 3 | using App1.Views; 4 | using NewLife.Log; 5 | using Xamarin.Forms; 6 | using Xamarin.Forms.Xaml; 7 | 8 | namespace App1 9 | { 10 | public partial class App : Application 11 | { 12 | 13 | public App() 14 | { 15 | // 可以使用雷电模拟器测试,启动进入桌面时,PC上迅速执行 adb tcpip 5555 16 | 17 | var log = new NetworkLog { Server = "udp://255.255.255.255:514" }; 18 | XTrace.Log = new CompositeLog(XTrace.Log, log); 19 | XTrace.WriteLine("App"); 20 | 21 | InitializeComponent(); 22 | 23 | DependencyService.Register(); 24 | MainPage = new AppShell(); 25 | } 26 | 27 | protected override void OnStart() 28 | { 29 | XTrace.WriteLine("OnStart"); 30 | } 31 | 32 | protected override void OnSleep() 33 | { 34 | XTrace.WriteLine("OnSleep"); 35 | } 36 | 37 | protected override void OnResume() 38 | { 39 | XTrace.WriteLine("OnResume"); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /App1/App1/App1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /App1/App1/AppShell.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using App1.ViewModels; 4 | using App1.Views; 5 | using Xamarin.Forms; 6 | 7 | namespace App1 8 | { 9 | public partial class AppShell : Xamarin.Forms.Shell 10 | { 11 | public AppShell() 12 | { 13 | InitializeComponent(); 14 | Routing.RegisterRoute(nameof(ItemDetailPage), typeof(ItemDetailPage)); 15 | Routing.RegisterRoute(nameof(NewItemPage), typeof(NewItemPage)); 16 | } 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /App1/App1/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using Xamarin.Forms.Xaml; 2 | 3 | [assembly: XamlCompilation(XamlCompilationOptions.Compile)] -------------------------------------------------------------------------------- /App1/App1/GettingStarted.txt: -------------------------------------------------------------------------------- 1 | Welcome to Xamarin.Forms! Here are some tips to get started building your app. 2 | 3 | Building Your App UI 4 | -------------------- 5 | 6 | XAML Hot Reload quickly applies UI changes as you make them to your running app. 7 | This is the most productive way to preview and iteratively create your UI. 8 | 9 | Try it out: 10 | 11 | 1. Run the app by clicking the Start Debugging (play) button in the above toolbar. 12 | 2. Open \Views\AboutPage.xaml. 13 | Don't stop the app - keep it running while making changes. 14 | 3. Change something! Hint: change the Accent color on line 14 from "#96d1ff" to "Pink". 15 | 4. Watch the About screen update on the device or emulator, with the logo background now pink. 16 | 17 | Keep going and try more changes! 18 | 19 | QuickStart Guide 20 | ---------------- 21 | 22 | Learn more of the fundamentals for building apps with Xamarin here: https://aka.ms/xamarin-quickstart 23 | 24 | Your App Shell 25 | -------------- 26 | 27 | This template uses Shell, an app container that reduces the complexity of your apps by providing fundamental features including: 28 | 29 | - A single place to describe the app's visual hierarchy. 30 | - Common navigation such as a flyout menu and tabs. 31 | - A URI-based navigation scheme that permits navigation to any page in the application. 32 | - An integrated search handler. 33 | 34 | Open AppShell.xaml to begin exploring. To learn more about Shell visit: https://docs.microsoft.com/xamarin/xamarin-forms/app-fundamentals/shell/introduction 35 | -------------------------------------------------------------------------------- /App1/App1/Models/Item.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace App1.Models 4 | { 5 | public class Item 6 | { 7 | public string Id { get; set; } 8 | public string Text { get; set; } 9 | public string Description { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /App1/App1/Services/IDataStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | namespace App1.Services 6 | { 7 | public interface IDataStore 8 | { 9 | Task AddItemAsync(T item); 10 | Task UpdateItemAsync(T item); 11 | Task DeleteItemAsync(string id); 12 | Task GetItemAsync(string id); 13 | Task> GetItemsAsync(bool forceRefresh = false); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /App1/App1/ViewModels/AboutViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Input; 3 | using Xamarin.Essentials; 4 | using Xamarin.Forms; 5 | 6 | namespace App1.ViewModels 7 | { 8 | public class AboutViewModel : BaseViewModel 9 | { 10 | public AboutViewModel() 11 | { 12 | Title = "About"; 13 | OpenWebCommand = new Command(async () => await Browser.OpenAsync("https://aka.ms/xamarin-quickstart")); 14 | } 15 | 16 | public ICommand OpenWebCommand { get; } 17 | } 18 | } -------------------------------------------------------------------------------- /App1/App1/ViewModels/ItemDetailViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Threading.Tasks; 4 | using App1.Models; 5 | using Xamarin.Forms; 6 | 7 | namespace App1.ViewModels 8 | { 9 | [QueryProperty(nameof(ItemId), nameof(ItemId))] 10 | public class ItemDetailViewModel : BaseViewModel 11 | { 12 | private string itemId; 13 | private string text; 14 | private string description; 15 | public string Id { get; set; } 16 | 17 | public string Text 18 | { 19 | get => text; 20 | set => SetProperty(ref text, value); 21 | } 22 | 23 | public string Description 24 | { 25 | get => description; 26 | set => SetProperty(ref description, value); 27 | } 28 | 29 | public string ItemId 30 | { 31 | get 32 | { 33 | return itemId; 34 | } 35 | set 36 | { 37 | itemId = value; 38 | LoadItemId(value); 39 | } 40 | } 41 | 42 | public async void LoadItemId(string itemId) 43 | { 44 | try 45 | { 46 | var item = await DataStore.GetItemAsync(itemId); 47 | Id = item.Id; 48 | Text = item.Text; 49 | Description = item.Description; 50 | } 51 | catch (Exception) 52 | { 53 | Debug.WriteLine("Failed to Load Item"); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /App1/App1/ViewModels/LoginViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using App1.Views; 5 | using Xamarin.Forms; 6 | 7 | namespace App1.ViewModels 8 | { 9 | public class LoginViewModel : BaseViewModel 10 | { 11 | public Command LoginCommand { get; } 12 | 13 | public LoginViewModel() 14 | { 15 | LoginCommand = new Command(OnLoginClicked); 16 | } 17 | 18 | private async void OnLoginClicked(object obj) 19 | { 20 | // Prefixing with `//` switches to a different navigation stack instead of pushing to the active one 21 | await Shell.Current.GoToAsync($"//{nameof(AboutPage)}"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /App1/App1/Views/AboutPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using Xamarin.Forms; 4 | using Xamarin.Forms.Xaml; 5 | 6 | namespace App1.Views 7 | { 8 | public partial class AboutPage : ContentPage 9 | { 10 | public AboutPage() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /App1/App1/Views/ItemDetailPage.xaml: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /App1/App1/Views/ItemDetailPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using App1.ViewModels; 3 | using Xamarin.Forms; 4 | 5 | namespace App1.Views 6 | { 7 | public partial class ItemDetailPage : ContentPage 8 | { 9 | public ItemDetailPage() 10 | { 11 | InitializeComponent(); 12 | BindingContext = new ItemDetailViewModel(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /App1/App1/Views/ItemsPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using App1.Models; 8 | using App1.ViewModels; 9 | using App1.Views; 10 | using Xamarin.Forms; 11 | using Xamarin.Forms.Xaml; 12 | 13 | namespace App1.Views 14 | { 15 | public partial class ItemsPage : ContentPage 16 | { 17 | ItemsViewModel _viewModel; 18 | 19 | public ItemsPage() 20 | { 21 | InitializeComponent(); 22 | 23 | BindingContext = _viewModel = new ItemsViewModel(); 24 | } 25 | 26 | protected override void OnAppearing() 27 | { 28 | base.OnAppearing(); 29 | _viewModel.OnAppearing(); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /App1/App1/Views/LoginPage.xaml: -------------------------------------------------------------------------------- 1 |  2 | 9 | 10 | 11 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /App1/App1/Views/NewItemPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using App1.Models; 5 | using App1.ViewModels; 6 | using Xamarin.Forms; 7 | using Xamarin.Forms.Xaml; 8 | 9 | namespace App1.Views 10 | { 11 | public partial class NewItemPage : ContentPage 12 | { 13 | public Item Item { get; set; } 14 | 15 | public NewItemPage() 16 | { 17 | InitializeComponent(); 18 | BindingContext = new NewItemViewModel(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Doc/WebSocket双向通信.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/WebSocket双向通信.pcapng -------------------------------------------------------------------------------- /Doc/XCode.emmx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/XCode.emmx -------------------------------------------------------------------------------- /Doc/chunk分析.eddx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/chunk分析.eddx -------------------------------------------------------------------------------- /Doc/leaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/leaf.png -------------------------------------------------------------------------------- /Doc/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/logo.ico -------------------------------------------------------------------------------- /Doc/newlife.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/newlife.pfx -------------------------------------------------------------------------------- /Doc/newlife.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/newlife.snk -------------------------------------------------------------------------------- /Doc/插入字段逻辑.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/插入字段逻辑.png -------------------------------------------------------------------------------- /Doc/降采样/LTOB降采样.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/降采样/LTOB降采样.png -------------------------------------------------------------------------------- /Doc/降采样/LTOB降采样.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/降采样/LTOB降采样.xlsx -------------------------------------------------------------------------------- /Doc/降采样/LTTB降采样.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/降采样/LTTB降采样.png -------------------------------------------------------------------------------- /Doc/降采样/LTTB降采样.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Doc/降采样/LTTB降采样.xlsx -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 新生命开发团队 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NewLife.Core/Algorithms/AlignModes.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Algorithms; 2 | 3 | /// 4 | /// 对齐模型。数据采样时X轴对齐 5 | /// 6 | public enum AlignModes 7 | { 8 | /// 9 | /// 不对齐,原始值 10 | /// 11 | None, 12 | 13 | /// 14 | /// 左对齐 15 | /// 16 | Left, 17 | 18 | /// 19 | /// 中间对齐 20 | /// 21 | Center, 22 | 23 | /// 24 | /// 右对齐 25 | /// 26 | Right, 27 | } -------------------------------------------------------------------------------- /NewLife.Core/Algorithms/BilinearInterpolation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Algorithms 4 | { 5 | /// 6 | /// 双线性插值 7 | /// 8 | public class BilinearInterpolation 9 | { 10 | public static Single[,] Process(Single[,] array, Int32 timeLength, Int32 valueLength) 11 | { 12 | var rs = new Single[timeLength, valueLength]; 13 | 14 | var scale1 = (Single)array.GetLength(0) / timeLength; 15 | var scale2 = (Single)array.GetLength(1) / valueLength; 16 | 17 | for (var i = 0; i < timeLength; i++) 18 | { 19 | for (var j = 0; j < valueLength; j++) 20 | { 21 | var d1 = i * scale1; 22 | var d2 = j * scale2; 23 | var n1 = (Int32)Math.Floor(d1); 24 | var n2 = (Int32)Math.Floor(d2); 25 | var leftUp = (d1 - n1) * (d2 - n2); 26 | var rightUp = (n1 + 1 - d1) * (d2 - n2); 27 | var rightDown = (n1 + 1 - d1) * (n2 + 1 - d2); 28 | var leftDown = (d1 - n1) * (n2 + 1 - d2); 29 | rs[i, j] = 30 | array[n1, n2] * rightDown + 31 | array[n1 + 1, n2] * leftDown + 32 | array[n1 + 1, n2 + 1] * leftUp + 33 | array[n1, n2 + 1] * rightUp; 34 | } 35 | } 36 | 37 | return rs; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /NewLife.Core/Algorithms/BucketModes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NewLife.Algorithms 7 | { 8 | internal class BucketModes 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /NewLife.Core/Algorithms/IInterpolation.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Data; 2 | 3 | namespace NewLife.Algorithms; 4 | 5 | /// 6 | /// 插值算法 7 | /// 8 | public interface IInterpolation 9 | { 10 | /// 11 | /// 插值处理 12 | /// 13 | /// 数据 14 | /// 上一个点索引 15 | /// 下一个点索引 16 | /// 当前点时间值 17 | /// 18 | Double Process(TimePoint[] data, Int32 prev, Int32 next, Int64 current); 19 | } -------------------------------------------------------------------------------- /NewLife.Core/Algorithms/LinearInterpolation.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Data; 2 | 3 | namespace NewLife.Algorithms; 4 | 5 | /// 6 | /// 线性插值 7 | /// 8 | public class LinearInterpolation : IInterpolation 9 | { 10 | /// 11 | /// 插值处理 12 | /// 13 | /// 数据 14 | /// 上一个点索引 15 | /// 下一个点索引 16 | /// 当前点时间值 17 | /// 18 | public Double Process(TimePoint[] data, Int32 prev, Int32 next, Int64 current) 19 | { 20 | var dt = (data[next].Value - data[prev].Value) / (data[next].Time - data[prev].Time); 21 | return data[prev].Value + (current - data[prev].Time) * dt; 22 | } 23 | } -------------------------------------------------------------------------------- /NewLife.Core/Caching/CacheProvider.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Caching; 2 | 3 | /// 分布式缓存架构服务。提供基础缓存及队列服务 4 | public class CacheProvider : ICacheProvider 5 | { 6 | #region 属性 7 | /// 全局缓存。各功能模块跨进程共享数据,分布式部署时可用Redis,需要考虑序列化成本。默认单机使用内存缓存 8 | public ICache Cache { get; set; } 9 | 10 | /// 应用内本地缓存。默认内存缓存,无需考虑对象序列化成本,缺点是不支持跨进程共享数据 11 | public ICache InnerCache { get; set; } 12 | #endregion 13 | 14 | #region 构造 15 | /// 使用默认缓存实例化 16 | public CacheProvider() 17 | { 18 | var cache = Caching.Cache.Default ?? new MemoryCache(); 19 | Cache = cache; 20 | InnerCache = cache; 21 | } 22 | #endregion 23 | 24 | #region 方法 25 | /// 获取队列。各功能模块跨进程共用的队列 26 | /// 消息类型 27 | /// 主题 28 | /// 消费组 29 | /// 30 | public virtual IProducerConsumer GetQueue(String topic, String? group = null) => Cache.GetQueue(topic); 31 | 32 | /// 获取内部队列。默认内存队列 33 | /// 消息类型 34 | /// 主题 35 | /// 36 | public virtual IProducerConsumer GetInnerQueue(String topic) => InnerCache.GetQueue(topic); 37 | 38 | /// 申请分布式锁 39 | /// 要锁定的键值。建议加上应用模块等前缀以避免冲突 40 | /// 遇到冲突时等待的最大时间 41 | /// 42 | public virtual IDisposable? AcquireLock(String lockKey, Int32 msTimeout) => Cache.AcquireLock(lockKey, msTimeout); 43 | #endregion 44 | } -------------------------------------------------------------------------------- /NewLife.Core/Caching/IProducerConsumer.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Caching; 2 | 3 | /// 轻量级生产者消费者接口 4 | /// 5 | /// 不一定支持Ack机制;也不支持消息体与消息键分离 6 | /// 7 | /// 8 | public interface IProducerConsumer 9 | { 10 | /// 元素个数 11 | Int32 Count { get; } 12 | 13 | /// 集合是否为空 14 | Boolean IsEmpty { get; } 15 | 16 | /// 生产添加 17 | /// 18 | /// 19 | Int32 Add(params T[] values); 20 | 21 | /// 消费获取一批 22 | /// 23 | /// 24 | IEnumerable Take(Int32 count = 1); 25 | 26 | /// 消费获取一个 27 | /// 超时。默认0秒,永久等待 28 | /// 29 | T? TakeOne(Int32 timeout = 0); 30 | 31 | /// 异步消费获取一个 32 | /// 超时。单位秒,0秒表示永久等待 33 | /// 34 | Task TakeOneAsync(Int32 timeout = 0); 35 | 36 | /// 异步消费获取一个 37 | /// 超时。单位秒,0秒表示永久等待 38 | /// 取消通知 39 | /// 40 | Task TakeOneAsync(Int32 timeout, CancellationToken cancellationToken); 41 | 42 | /// 确认消费 43 | /// 44 | /// 45 | Int32 Acknowledge(params String[] keys); 46 | } -------------------------------------------------------------------------------- /NewLife.Core/Collections/ConcurrentHashSet.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Concurrent; 3 | 4 | namespace NewLife.Collections; 5 | 6 | /// 并行哈希集合 7 | /// 8 | /// 主要用于频繁添加删除而又要遍历的场合 9 | /// 10 | public class ConcurrentHashSet : IEnumerable where T : notnull 11 | { 12 | private readonly ConcurrentDictionary _dic = new(); 13 | 14 | /// 是否空集合 15 | public Boolean IsEmpty => _dic.IsEmpty; 16 | 17 | /// 元素个数 18 | public Int32 Count => _dic.Count; 19 | 20 | /// 是否包含元素 21 | /// 22 | /// 23 | public Boolean Contain(T item) => _dic.ContainsKey(item); 24 | 25 | /// 尝试添加 26 | /// 27 | /// 28 | public Boolean TryAdd(T item) => _dic.TryAdd(item, 0); 29 | 30 | /// 尝试删除 31 | /// 32 | /// 33 | public Boolean TryRemove(T item) => _dic.TryRemove(item, out _); 34 | 35 | #region IEnumerable 成员 36 | IEnumerator IEnumerable.GetEnumerator() => _dic.Keys.GetEnumerator(); 37 | #endregion 38 | 39 | #region IEnumerable 成员 40 | IEnumerator IEnumerable.GetEnumerator() => _dic.Keys.GetEnumerator(); 41 | #endregion 42 | } -------------------------------------------------------------------------------- /NewLife.Core/Collections/IDictionarySource.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Collections; 2 | 3 | /// 4 | /// 字典数据源接口。定义该模型类支持输出名值字典,便于序列化传输 5 | /// 6 | public interface IDictionarySource 7 | { 8 | /// 9 | /// 把对象转为名值字典,便于序列化传输 10 | /// 11 | /// 12 | IDictionary ToDictionary(); 13 | } -------------------------------------------------------------------------------- /NewLife.Core/Collections/NullableDictionary.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Collections; 2 | 3 | /// 可空字典。获取数据时如果指定键不存在可返回空而不是抛出异常 4 | /// 5 | /// 6 | public class NullableDictionary : Dictionary, IDictionary where TKey : notnull 7 | { 8 | /// 实例化一个可空字典 9 | public NullableDictionary() { } 10 | 11 | /// 指定比较器实例化一个可空字典 12 | /// 13 | public NullableDictionary(IEqualityComparer comparer) : base(comparer) { } 14 | 15 | /// 实例化一个可空字典 16 | /// 17 | public NullableDictionary(IDictionary dic) : base(dic) { } 18 | 19 | /// 实例化一个可空字典 20 | /// 21 | /// 22 | public NullableDictionary(IDictionary dic, IEqualityComparer comparer) : base(dic, comparer) { } 23 | 24 | /// 获取 或 设置 数据 25 | /// 26 | /// 27 | public new TValue this[TKey item] 28 | { 29 | get 30 | { 31 | if (TryGetValue(item, out var v)) return v; 32 | 33 | return default!; 34 | } 35 | set 36 | { 37 | base[item] = value; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /NewLife.Core/Configuration/ConfigCacheLevel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NewLife.Configuration 7 | { 8 | /// 配置数据缓存等级 9 | public enum ConfigCacheLevel 10 | { 11 | /// 不缓存 12 | NoCache, 13 | 14 | /// Json格式缓存 15 | Json, 16 | 17 | /// 加密缓存 18 | Encrypted, 19 | } 20 | } -------------------------------------------------------------------------------- /NewLife.Core/Configuration/GetConfigCallback.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Configuration; 2 | 3 | /// 获取配置委托。便于集成配置中心 4 | /// 5 | /// 6 | public delegate String? GetConfigCallback(String key); -------------------------------------------------------------------------------- /NewLife.Core/Configuration/IConfigMapping.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Configuration 2 | { 3 | /// 配置映射接口。用于自定义映射配置树到当前对象 4 | /// 5 | /// 整体配置数据改变时触发调用该接口,但不表示当前对象所绑定路径的配置数据有改变,用户需要自己判断所属配置数据是否已改变。 6 | /// 7 | public interface IConfigMapping 8 | { 9 | /// 映射配置树到当前对象 10 | /// 配置提供者 11 | /// 配置数据段 12 | void MapConfig(IConfigProvider provider, IConfigSection section); 13 | } 14 | } -------------------------------------------------------------------------------- /NewLife.Core/Data/DbRow.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | using System.Xml.Serialization; 3 | 4 | namespace NewLife.Data; 5 | 6 | /// 数据行 7 | /// 8 | /// 文档 https://newlifex.com/core/dbtable 9 | /// 10 | /// 构造数据行 11 | /// 12 | /// 13 | public readonly struct DbRow(DbTable table, Int32 index) : IModel 14 | { 15 | #region 属性 16 | /// 数据表 17 | [XmlIgnore, IgnoreDataMember] 18 | public readonly DbTable Table { get; } = table; 19 | 20 | /// 行索引 21 | public readonly Int32 Index { get; } = index; 22 | 23 | #endregion 24 | 25 | #region 索引器 26 | /// 基于列索引访问 27 | /// 28 | /// 29 | public readonly Object? this[Int32 column] 30 | { 31 | get => Table.Rows?[Index][column]; 32 | set 33 | { 34 | var rows = Table.Rows; 35 | if (rows != null) rows[Index][column] = value; 36 | } 37 | } 38 | 39 | /// 基于列名访问 40 | /// 41 | /// 42 | public Object? this[String name] { get => this[Table.GetColumn(name)]; set => this[Table.GetColumn(name)] = value; } 43 | #endregion 44 | 45 | #region 高级扩展 46 | /// 读取指定行的字段值 47 | /// 48 | /// 49 | /// 50 | public readonly T? Get(String name) => Table.Get(Index, name); 51 | #endregion 52 | } -------------------------------------------------------------------------------- /NewLife.Core/Data/GeoArea.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Data 4 | { 5 | /// 地理区域 6 | public class GeoArea 7 | { 8 | #region 属性 9 | /// 编码 10 | public Int32 Code { get; set; } 11 | 12 | /// 名称 13 | public String Name { get; set; } 14 | 15 | /// 父级 16 | public Int32 ParentCode { get; set; } 17 | 18 | /// 中心 19 | public String Center { get; set; } 20 | 21 | /// 边界 22 | public String Polyline { get; set; } 23 | 24 | /// 级别 25 | public String Level { get; set; } 26 | #endregion 27 | 28 | /// 已重载。 29 | /// 30 | public override String ToString() => $"{Code} {Name}"; 31 | } 32 | } -------------------------------------------------------------------------------- /NewLife.Core/Data/GeoPoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Data 4 | { 5 | /// 经纬度坐标 6 | public class GeoPoint 7 | { 8 | #region 属性 9 | /// 经度 10 | public Double Longitude { get; set; } 11 | 12 | /// 纬度 13 | public Double Latitude { get; set; } 14 | #endregion 15 | 16 | #region 构造 17 | /// 经纬度坐标 18 | public GeoPoint() { } 19 | 20 | /// 实例化经纬度坐标 21 | /// 22 | /// 23 | public GeoPoint(Double longitude, Double latitude) 24 | { 25 | Longitude = longitude; 26 | Latitude = latitude; 27 | } 28 | 29 | /// 经纬度坐标 30 | /// 31 | public GeoPoint(String location) 32 | { 33 | if (!location.IsNullOrEmpty()) 34 | { 35 | var ss = location.Split(','); 36 | if (ss.Length >= 2) 37 | { 38 | Longitude = ss[0].ToDouble(); 39 | Latitude = ss[1].ToDouble(); 40 | } 41 | } 42 | } 43 | #endregion 44 | 45 | /// 已重载 46 | /// 47 | public override String ToString() => $"{Longitude},{Latitude}"; 48 | } 49 | } -------------------------------------------------------------------------------- /NewLife.Core/Data/IData.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace NewLife.Data; 4 | 5 | /// 数据帧接口。用于网络通信领域,定义数据帧的必要字段 6 | public interface IData 7 | { 8 | #region 属性 9 | /// 原始数据包 10 | IPacket? Packet { get; set; } 11 | 12 | /// 远程地址 13 | IPEndPoint? Remote { get; set; } 14 | 15 | /// 解码后的消息 16 | Object? Message { get; set; } 17 | 18 | /// 用户自定义数据 19 | Object? UserState { get; set; } 20 | #endregion 21 | } -------------------------------------------------------------------------------- /NewLife.Core/Data/IMemoryEncoder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Data 4 | { 5 | /// 内存字节流编码器 6 | public interface IMemoryEncoder 7 | { 8 | /// 数值转内存字节流 9 | /// 10 | /// 11 | Memory Encode(Object value); 12 | 13 | /// 内存字节流转对象 14 | /// 15 | /// 16 | /// 17 | Object Decode(Memory data, Type type); 18 | } 19 | } -------------------------------------------------------------------------------- /NewLife.Core/Data/IModel.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Data; 2 | 3 | /// 模型数据接口,支持索引器读写属性 4 | /// 5 | /// 可借助反射取得属性列表成员,从而对实体模型属性进行读写操作,避免反射带来的负担。 6 | /// 常用于WebApi模型类以及XCode数据实体类,也用于魔方接口拷贝。 7 | /// 8 | /// 逐步替代 IExtend 的大部分使用场景 9 | /// 10 | public interface IModel 11 | { 12 | /// 设置 或 获取 数据项 13 | /// 14 | /// 15 | Object? this[String key] { get; set; } 16 | } -------------------------------------------------------------------------------- /NewLife.Core/Data/IndexRange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Data 4 | { 5 | /// 6 | /// 范围 7 | /// 8 | public struct IndexRange 9 | { 10 | /// 11 | /// 开始,包含 12 | /// 13 | public Int32 Start; 14 | 15 | /// 16 | /// 结束,不包含 17 | /// 18 | public Int32 End; 19 | 20 | /// 21 | /// 已重载 22 | /// 23 | /// 24 | public override String ToString() => $"({Start}, {End})"; 25 | } 26 | } -------------------------------------------------------------------------------- /NewLife.Core/Data/TimePoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Data; 4 | 5 | /// 6 | /// 时序点,用于时序数据计算 7 | /// 8 | public struct TimePoint 9 | { 10 | /// 11 | /// 时间 12 | /// 13 | public Int64 Time; 14 | 15 | /// 16 | /// 数值 17 | /// 18 | public Double Value; 19 | 20 | /// 21 | /// 已重载 22 | /// 23 | /// 24 | public override String ToString() => $"({Time}, {Value})"; 25 | } 26 | 27 | ///// 28 | ///// 时序点,用于时序数据计算 29 | ///// 30 | //public struct LongTimePoint 31 | //{ 32 | // /// 33 | // /// 时间 34 | // /// 35 | // public Int64 Time; 36 | 37 | // /// 38 | // /// 数值 39 | // /// 40 | // public Double Value; 41 | //} -------------------------------------------------------------------------------- /NewLife.Core/Expressions/IndexInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace NewLife.Expressions 5 | { 6 | class IndexInfoResult 7 | { 8 | public IndexInfoResult(String indexMark) 9 | { 10 | Mark = indexMark; 11 | IndexInfos = new List(); 12 | } 13 | 14 | public String Mark { get; set; } 15 | 16 | public IList IndexInfos { get; private set; } 17 | } 18 | 19 | class IndexInfo 20 | { 21 | public IndexInfo(String stockCode, Int32 value) 22 | { 23 | StockCode = stockCode; 24 | Value = value; 25 | } 26 | 27 | public IndexInfo(String code) => StockCode = code; 28 | 29 | public String StockCode { get; set; } 30 | 31 | public Int32? Value { get; set; } 32 | } 33 | } -------------------------------------------------------------------------------- /NewLife.Core/Extension/ConcurrentDictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | 3 | namespace System; 4 | 5 | /// 并发字典扩展 6 | public static class ConcurrentDictionaryExtensions 7 | { 8 | /// 从并发字典中删除 9 | /// 10 | /// 11 | /// 12 | /// 13 | /// 14 | public static Boolean Remove(this ConcurrentDictionary dict, TKey key) where TKey : notnull => dict.TryRemove(key, out _); 15 | } -------------------------------------------------------------------------------- /NewLife.Core/Extension/ListExtension.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace System.Collections.Generic; 5 | 6 | /// 扩展List,支持遍历中修改元素 7 | public static class ListExtension 8 | { 9 | /// 线程安全,搜索并返回第一个,支持遍历中修改元素 10 | /// 实体列表 11 | /// 条件 12 | /// 13 | public static T? Find(this IList list, Predicate match) 14 | { 15 | if (list is List list2) return list2.Find(match); 16 | 17 | return list.ToArray().FirstOrDefault(e => match(e)); 18 | } 19 | 20 | /// 线程安全,搜索并返回第一个,支持遍历中修改元素 21 | /// 实体列表 22 | /// 条件 23 | /// 24 | public static IList FindAll(this IList list, Predicate match) 25 | { 26 | if (list is List list2) return list2.FindAll(match); 27 | 28 | return list.ToArray().Where(e => match(e)).ToList(); 29 | } 30 | } -------------------------------------------------------------------------------- /NewLife.Core/Http/ControllerHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Reflection; 3 | using NewLife.Model; 4 | using NewLife.Reflection; 5 | using NewLife.Remoting; 6 | 7 | namespace NewLife.Http; 8 | 9 | /// 控制器处理器 10 | public class ControllerHandler : IHttpHandler 11 | { 12 | #region 属性 13 | /// 控制器类型 14 | public Type? ControllerType { get; set; } 15 | #endregion 16 | 17 | /// 处理请求 18 | /// 19 | public virtual void ProcessRequest(IHttpContext context) 20 | { 21 | var type = ControllerType; 22 | if (type == null) return; 23 | 24 | var ss = context.Path.Split('/'); 25 | var methodName = ss.Length >= 3 ? ss[2] : null; 26 | 27 | // 优先使用服务提供者创建控制器对象,以便控制器构造函数注入 28 | var controller = context.ServiceProvider?.CreateInstance(type) ?? type.CreateInstance(); 29 | 30 | var method = methodName == null ? null : type.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase); 31 | if (method == null) throw new ApiException(ApiCode.NotFound, $"Cannot find operation [{methodName}] within controller [{type.FullName}]"); 32 | 33 | var result = controller.InvokeWithParams(method, context.Parameters as IDictionary); 34 | if (result != null) 35 | context.Response.SetResult(result); 36 | } 37 | } -------------------------------------------------------------------------------- /NewLife.Core/Http/FormFile.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Http; 2 | 3 | /// 表单部分 4 | public class FormFile 5 | { 6 | #region 属性 7 | /// 名称 8 | public String Name { get; set; } = null!; 9 | 10 | /// 内容部署 11 | public String? ContentDisposition { get; set; } 12 | 13 | /// 内容类型 14 | public String? ContentType { get; set; } 15 | 16 | /// 文件名 17 | public String? FileName { get; set; } 18 | 19 | /// 数据 20 | public Byte[]? Data { get; set; } 21 | 22 | /// 长度 23 | public Int64 Length => Data?.Length ?? 0; 24 | #endregion 25 | 26 | /// 打开数据读取流 27 | /// 28 | public Stream? OpenReadStream() => Data == null ? null : new MemoryStream(Data); 29 | 30 | /// 保存到文件 31 | /// 32 | public void SaveToFile(String? fileName = null) 33 | { 34 | if (fileName.IsNullOrEmpty()) fileName = FileName; 35 | if (fileName.IsNullOrEmpty()) throw new ArgumentNullException(nameof(fileName)); 36 | if (Data == null) throw new ArgumentNullException(nameof(Data)); 37 | 38 | fileName.EnsureDirectory(true); 39 | 40 | using var fs = File.OpenWrite(fileName.GetFullPath()); 41 | //Data.CopyTo(fs); 42 | fs.Write(Data); 43 | fs.SetLength(fs.Position); 44 | fs.Flush(); 45 | } 46 | } -------------------------------------------------------------------------------- /NewLife.Core/Http/IHttpClientFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | 4 | namespace NewLife.Http 5 | { 6 | /// HttpClient工厂 7 | public interface IHttpClientFactory 8 | { 9 | /// 创建HttpClient 10 | /// 11 | /// 12 | HttpClient CreateClient(String name); 13 | } 14 | } -------------------------------------------------------------------------------- /NewLife.Core/Http/IHttpFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | 3 | namespace NewLife.Http; 4 | 5 | /// Http过滤器,拦截请求前后 6 | public interface IHttpFilter 7 | { 8 | /// 请求前 9 | /// 客户端 10 | /// 请求消息 11 | /// 状态数据 12 | /// 取消通知 13 | /// 14 | Task OnRequest(HttpClient client, HttpRequestMessage request, Object? state, CancellationToken cancellationToken); 15 | 16 | /// 获取响应后 17 | /// 客户端 18 | /// 响应消息 19 | /// 状态数据 20 | /// 取消通知 21 | /// 22 | Task OnResponse(HttpClient client, HttpResponseMessage response, Object? state, CancellationToken cancellationToken); 23 | 24 | /// 发生错误时 25 | /// 客户端 26 | /// 异常 27 | /// 状态数据 28 | /// 取消通知 29 | /// 30 | Task OnError(HttpClient client, Exception exception, Object? state, CancellationToken cancellationToken); 31 | } -------------------------------------------------------------------------------- /NewLife.Core/Http/IHttpHost.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Http; 2 | 3 | /// Http主机服务 4 | public interface IHttpHost 5 | { 6 | /// 匹配处理器 7 | /// 8 | /// 9 | /// 10 | IHttpHandler? MatchHandler(String path, HttpRequest? request); 11 | } 12 | -------------------------------------------------------------------------------- /NewLife.Core/IO/IObjectInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using NewLife.Data; 3 | 4 | namespace NewLife.IO; 5 | 6 | /// 对象信息接口。代表文件存储对象,或者磁盘文件,也可以是目录 7 | public interface IObjectInfo 8 | { 9 | /// 名称 10 | String? Name { get; set; } 11 | 12 | /// 大小 13 | Int64 Length { get; set; } 14 | 15 | /// 时间 16 | DateTime Time { get; set; } 17 | 18 | /// 是否目录 19 | Boolean IsDirectory { get; set; } 20 | 21 | /// 数据 22 | IPacket? Data { get; set; } 23 | } 24 | 25 | /// 对象信息。代表文件存储对象,或者磁盘文件,也可以是目录 26 | [DebuggerDisplay("{Name} [{Length}]")] 27 | public class ObjectInfo : IObjectInfo 28 | { 29 | /// 名称 30 | public String? Name { get; set; } 31 | 32 | /// 大小 33 | public Int64 Length { get; set; } 34 | 35 | /// 时间 36 | public DateTime Time { get; set; } 37 | 38 | /// 是否目录 39 | public Boolean IsDirectory { get; set; } 40 | 41 | /// 数据 42 | public IPacket? Data { get; set; } 43 | } -------------------------------------------------------------------------------- /NewLife.Core/Json/JsonConfigFileAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Json 4 | { 5 | /// Json配置文件特性 6 | [AttributeUsage(AttributeTargets.Class)] 7 | public class JsonConfigFileAttribute : Attribute 8 | { 9 | private String _fileName; 10 | /// 配置文件名 11 | public String FileName { get { return _fileName; } set { _fileName = value; } } 12 | 13 | private Int32 _reloadTime; 14 | /// 重新加载时间。单位:毫秒 15 | public Int32 ReloadTime { get { return _reloadTime; } set { _reloadTime = value; } } 16 | 17 | /// 指定配置文件名 18 | /// 19 | public JsonConfigFileAttribute(String fileName) { FileName = fileName; } 20 | 21 | /// 指定配置文件名和重新加载时间(毫秒) 22 | /// 23 | /// 24 | public JsonConfigFileAttribute(String fileName, Int32 reloadTime) 25 | { 26 | FileName = fileName; 27 | ReloadTime = reloadTime; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /NewLife.Core/Log/ActionLog.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Log; 2 | 3 | /// 依托于动作的日志类 4 | public class ActionLog : Logger 5 | { 6 | /// 方法 7 | public Action Method { get; set; } 8 | 9 | /// 使用指定方法否则动作日志 10 | /// 11 | public ActionLog(Action action) => Method = action; 12 | 13 | /// 写日志 14 | /// 15 | /// 16 | /// 17 | protected override void OnWrite(LogLevel level, String format, params Object?[] args) => Method?.Invoke(format, args); 18 | 19 | /// 已重载 20 | /// 21 | public override String ToString() => Method + ""; 22 | } -------------------------------------------------------------------------------- /NewLife.Core/Log/ILog.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Log; 2 | 3 | /// 日志接口 4 | /// 5 | /// 文档 https://newlifex.com/core/log 6 | /// 7 | public interface ILog 8 | { 9 | /// 写日志 10 | /// 日志级别 11 | /// 格式化字符串 12 | /// 格式化参数 13 | void Write(LogLevel level, String format, params Object?[] args); 14 | 15 | /// 调试日志 16 | /// 格式化字符串 17 | /// 格式化参数 18 | void Debug(String format, params Object?[] args); 19 | 20 | /// 信息日志 21 | /// 格式化字符串 22 | /// 格式化参数 23 | void Info(String format, params Object?[] args); 24 | 25 | /// 警告日志 26 | /// 格式化字符串 27 | /// 格式化参数 28 | void Warn(String format, params Object?[] args); 29 | 30 | /// 错误日志 31 | /// 格式化字符串 32 | /// 格式化参数 33 | void Error(String format, params Object?[] args); 34 | 35 | /// 严重错误日志 36 | /// 格式化字符串 37 | /// 格式化参数 38 | void Fatal(String format, params Object?[] args); 39 | 40 | /// 是否启用日志 41 | Boolean Enable { get; set; } 42 | 43 | /// 日志等级,只输出大于等于该级别的日志,默认Info 44 | LogLevel Level { get; set; } 45 | } -------------------------------------------------------------------------------- /NewLife.Core/Log/ILogFeature.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Log; 2 | 3 | /// 写日志接口。支持写应用功能日志 4 | public interface ILogProvider 5 | { 6 | /// 写日志 7 | /// 动作 8 | /// 是否成功 9 | /// 内容 10 | void WriteLog(String action, Boolean success, String content); 11 | } 12 | 13 | /// 日志功能接口 14 | public interface ILogFeature 15 | { 16 | /// 日志。非空,默认为Logger.Null 17 | ILog Log { get; set; } 18 | } 19 | 20 | /// 日志功能扩展 21 | public static class LogFeatureExtensions 22 | { 23 | /// 写日志 24 | /// 日志功能 25 | /// 格式化字符串 26 | /// 格式化参数,特殊处理时间日期和异常对象 27 | public static void WriteLog(this ILogFeature logFeature, String format, params Object?[] args) => logFeature.Log?.Info(format, args); 28 | } -------------------------------------------------------------------------------- /NewLife.Core/Log/ITracerFeature.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Log; 2 | 3 | /// 日志功能接口 4 | public interface ITracerFeature 5 | { 6 | /// 性能追踪 7 | ITracer? Tracer { get; set; } 8 | } -------------------------------------------------------------------------------- /NewLife.Core/Log/LevelLog.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Log; 2 | 3 | /// 等级日志提供者,不同等级分不同日志输出 4 | public class LevelLog : Logger 5 | { 6 | private IDictionary _logs = new Dictionary(); 7 | 8 | /// 通过指定路径和文件格式来实例化等级日志,每个等级使用自己的日志输出 9 | /// 10 | /// 11 | public LevelLog(String logPath, String fileFormat) 12 | { 13 | foreach (var item in Enum.GetValues(typeof(LogLevel))) 14 | { 15 | if (item is LogLevel level && level is > LogLevel.All and < LogLevel.Off) 16 | { 17 | _logs[level] = new TextFileLog(logPath, false, fileFormat) { Level = level }; 18 | } 19 | } 20 | } 21 | 22 | /// 写日志 23 | /// 24 | /// 25 | /// 26 | protected override void OnWrite(LogLevel level, String format, params Object?[] args) 27 | { 28 | if (_logs.TryGetValue(level, out var log)) log.Write(level, format, args); 29 | } 30 | } -------------------------------------------------------------------------------- /NewLife.Core/Log/LogLevel.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace NewLife.Log 3 | { 4 | /// 日志等级 5 | public enum LogLevel : System.Byte 6 | { 7 | /// 打开所有日志记录 8 | All = 0, 9 | 10 | /// 最低调试。细粒度信息事件对调试应用程序非常有帮助 11 | Debug, 12 | 13 | /// 普通消息。在粗粒度级别上突出强调应用程序的运行过程 14 | Info, 15 | 16 | /// 警告 17 | Warn, 18 | 19 | /// 错误 20 | Error, 21 | 22 | /// 严重错误 23 | Fatal, 24 | 25 | /// 关闭所有日志记录 26 | Off = 0xFF 27 | } 28 | } -------------------------------------------------------------------------------- /NewLife.Core/Log/Readme.md: -------------------------------------------------------------------------------- 1 | ## 日志 2 | 统一ILog接口,内置控制台、文本文件、WinForm控件和网络日志等实现 3 | -------------------------------------------------------------------------------- /NewLife.Core/Log/TextControlLog.cs: -------------------------------------------------------------------------------- 1 | #if __WIN__ 2 | using System; 3 | using System.Windows.Forms; 4 | 5 | namespace NewLife.Log; 6 | 7 | /// 文本控件输出日志 8 | public class TextControlLog : Logger 9 | { 10 | /// 文本控件 11 | public Control? Control { get; set; } 12 | 13 | /// 最大行数,超过该行数讲清空文本控件。默认1000行 14 | public Int32 MaxLines { get; set; } = 1000; 15 | 16 | /// 写日志 17 | /// 18 | /// 19 | /// 20 | protected override void OnWrite(LogLevel level, String format, params Object?[] args) => WriteLog(Control, Format(format, args) + Environment.NewLine, MaxLines); 21 | 22 | /// 在WinForm控件上输出日志,主要考虑非UI线程操作 23 | /// 不是常用功能,为了避免干扰常用功能,保持UseWinForm开头 24 | /// 要绑定日志输出的WinForm控件 25 | /// 日志 26 | /// 最大行数 27 | public static void WriteLog(Control? control, String msg, Int32 maxLines = 1000) 28 | { 29 | if (control == null) return; 30 | 31 | if (control is not TextBoxBase txt) throw new XException("Unsupported control type {0}!", control.GetType()); 32 | 33 | txt.Append(msg, maxLines); 34 | } 35 | } 36 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Messaging/MessageEventArgs.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Data; 2 | 3 | namespace NewLife.Messaging; 4 | 5 | /// 收到消息时的事件参数 6 | public class MessageEventArgs : EventArgs 7 | { 8 | #region 属性 9 | /// 数据包 10 | public IPacket? Packet { get; set; } 11 | 12 | /// 消息 13 | public IMessage? Message { get; set; } 14 | 15 | /// 用户数据。比如远程地址等 16 | public Object? UserState { get; set; } 17 | #endregion 18 | 19 | #region 方法 20 | #endregion 21 | } -------------------------------------------------------------------------------- /NewLife.Core/Model/IFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NewLife.Reflection; 3 | 4 | namespace NewLife.Model 5 | { 6 | /// 用于创建对象的工厂接口 7 | /// 8 | public interface IFactory 9 | { 10 | /// 创建对象实例 11 | /// 12 | /// 13 | T Create(Object args = null); 14 | } 15 | 16 | /// 反射创建对象的工厂 17 | /// 18 | public class Factory : IFactory 19 | { 20 | /// 创建对象实例 21 | /// 22 | /// 23 | public virtual T Create(Object args = null) => (T)typeof(T).CreateInstance(); 24 | } 25 | } -------------------------------------------------------------------------------- /NewLife.Core/Model/IHandlerContext.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Collections; 2 | using NewLife.Data; 3 | 4 | namespace NewLife.Model; 5 | 6 | /// 处理器上下文 7 | public interface IHandlerContext //: IExtend 8 | { 9 | /// 管道 10 | IPipeline? Pipeline { get; set; } 11 | 12 | /// 上下文拥有者 13 | Object? Owner { get; set; } 14 | 15 | /// 读取管道过滤后最终处理消息 16 | /// 17 | void FireRead(Object message); 18 | 19 | /// 写入管道过滤后最终处理消息 20 | /// 21 | Int32 FireWrite(Object message); 22 | } 23 | 24 | /// 处理器上下文 25 | public class HandlerContext : IHandlerContext, IExtend 26 | { 27 | #region 属性 28 | /// 管道 29 | public IPipeline? Pipeline { get; set; } 30 | 31 | /// 上下文拥有者 32 | public Object? Owner { get; set; } 33 | 34 | /// 数据项 35 | public IDictionary Items { get; } = new NullableDictionary(); 36 | 37 | /// 设置 或 获取 数据项 38 | /// 39 | /// 40 | public Object? this[String key] { get => Items.TryGetValue(key, out var obj) ? obj : null; set => Items[key] = value; } 41 | #endregion 42 | 43 | #region 方法 44 | /// 读取管道过滤后最终处理消息 45 | /// 46 | public virtual void FireRead(Object message) { } 47 | 48 | /// 写入管道过滤后最终处理消息 49 | /// 50 | public virtual Int32 FireWrite(Object message) => 0; 51 | #endregion 52 | } -------------------------------------------------------------------------------- /NewLife.Core/Model/IManageUser.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Model; 2 | 3 | /// 用户接口 4 | public interface IManageUser 5 | { 6 | #region 属性 7 | /// 编号 8 | Int32 ID { get; set; } 9 | 10 | /// 名称 11 | String Name { get; set; } 12 | 13 | /// 昵称 14 | String? NickName { get; set; } 15 | 16 | /// 启用 17 | Boolean Enable { get; set; } 18 | #endregion 19 | } -------------------------------------------------------------------------------- /NewLife.Core/Model/IServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Model; 4 | 5 | /// 服务接口。 6 | /// 服务代理XAgent可以附加代理实现了IServer接口的服务。 7 | public interface IServer 8 | { 9 | /// 开始 10 | void Start(); 11 | 12 | /// 停止 13 | /// 关闭原因。便于日志分析 14 | void Stop(String? reason); 15 | } -------------------------------------------------------------------------------- /NewLife.Core/Model/IServiceScope.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | 3 | namespace NewLife.Model; 4 | 5 | /// 范围服务。该范围生命周期内,每个服务类型只有一个实例 6 | /// 7 | /// 满足Singleton和Scoped的要求,暂时无法满足Transient的要求(仍然只有一份)。 8 | /// 9 | public interface IServiceScope : IDisposable 10 | { 11 | /// 服务提供者 12 | IServiceProvider ServiceProvider { get; } 13 | } 14 | 15 | class MyServiceScope : IServiceScope, IServiceProvider 16 | { 17 | public IServiceProvider? MyServiceProvider { get; set; } 18 | 19 | public IServiceProvider ServiceProvider => this; 20 | 21 | private readonly ConcurrentDictionary _cache = new(); 22 | 23 | public void Dispose() 24 | { 25 | // 销毁所有缓存 26 | foreach (var item in _cache) 27 | { 28 | if (item.Value is IDisposable dsp) dsp.Dispose(); 29 | } 30 | } 31 | 32 | public Object? GetService(Type serviceType) 33 | { 34 | while (true) 35 | { 36 | // 查缓存,如果没有再获取一个并缓存起来 37 | if (_cache.TryGetValue(serviceType, out var service)) return service; 38 | 39 | service = MyServiceProvider?.GetService(serviceType); 40 | 41 | if (_cache.TryAdd(serviceType, service)) return service; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /NewLife.Core/Model/IServiceScopeFactory.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Model; 2 | 3 | /// 范围服务工厂 4 | public interface IServiceScopeFactory 5 | { 6 | /// 创建范围服务 7 | /// 8 | IServiceScope CreateScope(); 9 | } 10 | 11 | class MyServiceScopeFactory : IServiceScopeFactory 12 | { 13 | public IServiceProvider? ServiceProvider { get; set; } 14 | 15 | public IServiceScope CreateScope() => new MyServiceScope { MyServiceProvider = ServiceProvider }; 16 | } -------------------------------------------------------------------------------- /NewLife.Core/Net/IIPResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace NewLife.Net; 5 | 6 | /// IP地址提供者 7 | public interface IIPResolver 8 | { 9 | /// 获取IP地址的物理地址位置 10 | /// 11 | /// 12 | String GetAddress(IPAddress addr); 13 | } -------------------------------------------------------------------------------- /NewLife.Core/Net/INetHandler.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Data; 2 | 3 | namespace NewLife.Net; 4 | 5 | /// 网络数据处理器。可作为业务处理实现,也可以作为前置协议解析 6 | public interface INetHandler 7 | { 8 | /// 建立连接时初始化会话 9 | /// 会话 10 | void Init(INetSession session); 11 | 12 | /// 处理客户端发来的数据 13 | /// 14 | void Process(IData data); 15 | } 16 | -------------------------------------------------------------------------------- /NewLife.Core/Net/ISocket.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | using NewLife.Log; 3 | using NewLife.Model; 4 | 5 | namespace NewLife.Net; 6 | 7 | /// 基础Socket接口 8 | /// 9 | /// 封装所有基础接口的共有特性! 10 | /// 11 | /// 核心设计理念:事件驱动,接口统一,简单易用! 12 | /// 异常处理理念:确保主流程简单易用,特殊情况的异常通过事件处理! 13 | /// 14 | public interface ISocket : IDisposable2 15 | { 16 | #region 属性 17 | /// 名称。主要用于日志输出 18 | String Name { get; set; } 19 | 20 | /// 基础Socket对象 21 | Socket? Client { get; } 22 | 23 | /// 本地地址 24 | NetUri Local { get; set; } 25 | 26 | /// 端口 27 | Int32 Port { get; set; } 28 | 29 | /// 消息管道。收发消息都经过管道处理器,进行协议编码解码 30 | /// 31 | /// 1,接收数据解码时,从前向后通过管道处理器; 32 | /// 2,发送数据编码时,从后向前通过管道处理器; 33 | /// 34 | IPipeline? Pipeline { get; set; } 35 | 36 | /// 日志提供者 37 | ILog Log { get; set; } 38 | 39 | /// 是否输出发送日志。默认false 40 | Boolean LogSend { get; set; } 41 | 42 | /// 是否输出接收日志。默认false 43 | Boolean LogReceive { get; set; } 44 | 45 | /// APM性能追踪器 46 | ITracer? Tracer { get; set; } 47 | #endregion 48 | 49 | #region 方法 50 | /// 已重载。日志加上前缀 51 | /// 52 | /// 53 | void WriteLog(String format, params Object?[] args); 54 | #endregion 55 | 56 | #region 事件 57 | /// 错误发生/断开连接时 58 | event EventHandler Error; 59 | #endregion 60 | } -------------------------------------------------------------------------------- /NewLife.Core/Net/ISocketClient.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Net; 2 | 3 | /// Socket客户端 4 | /// 5 | /// 具备打开关闭 6 | /// 7 | public interface ISocketClient : ISocketRemote 8 | { 9 | #region 属性 10 | /// 超时。默认3000ms 11 | Int32 Timeout { get; set; } 12 | 13 | /// 是否活动 14 | Boolean Active { get; set; } 15 | #endregion 16 | 17 | #region 开关连接 18 | /// 打开连接 19 | /// 是否成功 20 | Boolean Open(); 21 | 22 | /// 打开连接 23 | /// 取消通知 24 | /// 是否成功 25 | Task OpenAsync(CancellationToken cancellationToken); 26 | 27 | /// 关闭连接 28 | /// 关闭原因。便于日志分析 29 | /// 是否成功 30 | Boolean Close(String reason); 31 | 32 | /// 关闭连接 33 | /// 关闭原因。便于日志分析 34 | /// 取消通知 35 | /// 是否成功 36 | Task CloseAsync(String reason, CancellationToken cancellationToken); 37 | 38 | /// 打开后触发。 39 | event EventHandler Opened; 40 | 41 | /// 关闭后触发。可实现掉线重连 42 | event EventHandler Closed; 43 | #endregion 44 | } -------------------------------------------------------------------------------- /NewLife.Core/Net/ISocketServer.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Model; 2 | 3 | namespace NewLife.Net; 4 | 5 | /// Socket服务器接口 6 | public interface ISocketServer : ISocket, IServer 7 | { 8 | /// 是否活动 9 | Boolean Active { get; } 10 | 11 | /// 会话超时时间。默认20*60秒 12 | /// 13 | /// 对于每一个会话连接,如果超过该时间仍然没有收到任何数据,则断开会话连接。 14 | /// 15 | Int32 SessionTimeout { get; set; } 16 | 17 | /// 会话集合。用地址端口作为标识,业务应用自己维持地址端口与业务主键的对应关系。 18 | IDictionary Sessions { get; } 19 | 20 | /// 新会话时触发 21 | event EventHandler NewSession; 22 | } -------------------------------------------------------------------------------- /NewLife.Core/Net/ISocketSession.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Net; 2 | 3 | /// 用于与对方进行通讯的Socket会话,仅具有收发功能,也专用于上层应用收发数据 4 | /// 5 | /// Socket会话发送数据不需要指定远程地址,因为内部已经具有。 6 | /// 接收数据时,Tcp接收全部数据,而Udp只接受来自所属远方的数据。 7 | /// 8 | /// Socket会话不具有连接和断开的能力,所以需要外部连接好之后再创建Socket会话。 9 | /// 但是会话可以销毁,来代替断开。 10 | /// 对于Udp额外创建的会话来说,仅仅销毁会话而已。 11 | /// 12 | /// 所以,它必须具有收发数据的能力。 13 | /// 14 | public interface ISocketSession : ISocketRemote 15 | { 16 | #region 属性 17 | /// Socket服务器。当前通讯所在的Socket服务器,其实是TcpServer/UdpServer 18 | ISocketServer Server { get; } 19 | #endregion 20 | } 21 | 22 | /// 会话事件参数 23 | public class SessionEventArgs : EventArgs 24 | { 25 | /// 会话 26 | public ISocketSession Session { get; set; } 27 | 28 | /// 实例化 29 | /// 30 | public SessionEventArgs(ISocketSession session) => Session = session; 31 | } -------------------------------------------------------------------------------- /NewLife.Core/Net/ITransport.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Data; 2 | 3 | namespace NewLife.Net; 4 | 5 | /// 帧数据传输接口 6 | /// 实现者确保数据以包的形式传输,屏蔽数据的粘包和拆包 7 | public interface ITransport : IDisposable 8 | { 9 | /// 超时 10 | Int32 Timeout { get; set; } 11 | 12 | /// 打开 13 | Boolean Open(); 14 | 15 | /// 关闭 16 | Boolean Close(); 17 | 18 | /// 写入数据 19 | /// 数据包 20 | Int32 Send(IPacket data); 21 | 22 | /// 读取数据 23 | /// 24 | IOwnerPacket? Receive(); 25 | 26 | /// 数据到达事件 27 | event EventHandler Received; 28 | } -------------------------------------------------------------------------------- /NewLife.Core/Net/NetException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Net 4 | { 5 | /// 网络异常 6 | [Serializable] 7 | public class NetException : XException 8 | { 9 | #region 构造 10 | /// 初始化 11 | public NetException() { } 12 | 13 | /// 初始化 14 | /// 15 | public NetException(String message) : base(message) { } 16 | 17 | /// 初始化 18 | /// 19 | /// 20 | public NetException(String format, params Object[] args) : base(format, args) { } 21 | 22 | /// 初始化 23 | /// 24 | /// 25 | public NetException(String message, Exception innerException) : base(message, innerException) { } 26 | 27 | /// 初始化 28 | /// 29 | public NetException(Exception innerException) : base((innerException?.Message), innerException) { } 30 | #endregion 31 | } 32 | } -------------------------------------------------------------------------------- /NewLife.Core/Net/Readme.md: -------------------------------------------------------------------------------- 1 | ## 新生命网络库 2 | 3 | 4 | ### 标准网络封包协议 5 | 经过十多年经验积累以及多方共同讨论,于昨晚凌晨通过了新生命团队的标准网络封包协议,作为网络库NewLife.Net中封包接口的标准实现。(强烈推荐使用标准网络封包协议,用户也可以根据业务需要去自己实现接口) 6 | 7 | 8 | **标准网络封包协议:1 Flag + 1 Sequence + 2 Length + N Payload** 9 | ** 10 | 1个字节标识位,标识请求、响应、错误、加密、压缩等; 11 | 1个字节序列号,用于请求响应包配对; 12 | 2个字节数据长度N,指示后续负载数据长度(不包含头部4个字节),解决粘包问题; 13 | N个字节负载数据,数据内容完全由业务决定,最大长度65535=64k。 14 | ** 15 | 16 | ** 17 | 该网络封包协议应用于服务端RPC通信、CS通信、Web端、移动端、硬件设备端,10年内不做改变!!! 18 | ** 19 | 20 | 21 | 相关讨论点: 22 | 1. **数据长度字段定长**。不同语言实现不便于使用7位压缩编码整数,并且头部定长非常有利于各种过滤器实现。 23 | 2. **数据长度定为2个字节**。2个字节可表示64k的负载数据,可满足99%的业务需要,超过64k的数据,完全可以由业务层进行划分解决。 24 | 3. **粘包问题**。封包协议实现类,根据长度字段拆分负载数据交给业务层,内部带有数据缓冲区,也可以把众多小包重新组合成为一个标准包交给业务层。 25 | 4. **非标干扰数据**。在一个标准包接收之外,可能收到干扰数据,此时可根据长度字段解包,绝大部分干扰数据因为不符合封包格式而被抛弃。 26 | 5. **GPRS网络数据干扰**。在物联网2G领域,运行商可能在标准包之后额外发送一些数据,此数据有可能导致后续解包连锁错误。封包实现带有500ms超时丢弃功能,此时间内未完成解包则清空缓冲区。 27 | 6. **物联网硬件设备实现**。固定4字节的头部长度,非常便于嵌入式C/C++实现协议。 28 | 7. **网页前端实现**。js可操作二进制实现该头部。 29 | 8. **HTML5增强**。HTML5强烈推荐使用WebSocket,无需使用标准封包协议再次封装。本封包协议实现将会避开WebSocket数据包,同一个Tcp端口仅对非WebSocket数据包解包。 30 | 31 | **特别说明**,讨论期间争议最大的莫过于干扰数据导致连续出错,结论如下: 32 | 1. 封包格式可以有效干掉干扰数据 33 | 2. 500ms超时后清空缓冲区,避免干扰数据残留在缓冲区里面影响后续标准包,除非干扰数据能够以小于500ms的速度不断进来 34 | 3. 间隔小于500ms的干扰数据将会摧毁整个封包协议,但是这种情况已经不是程序问题,而是用户网络问题!!! 35 | -------------------------------------------------------------------------------- /NewLife.Core/Net/ReceivedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using NewLife.Data; 3 | 4 | namespace NewLife.Net; 5 | 6 | /// 收到数据时的事件参数 7 | public class ReceivedEventArgs : EventArgs, IData 8 | { 9 | #region 属性 10 | /// 原始数据包 11 | /// 12 | /// Packet内部直接引用网络缓冲区,以实现零拷贝,并非全部数据都属于当前消息。 13 | /// 需要注意所有权,当前数据事件结束时回收,不应被外部引用。 14 | /// 15 | public IPacket? Packet { get; set; } 16 | 17 | /// 本地地址 18 | public IPAddress? Local { get; set; } 19 | 20 | /// 远程地址 21 | public IPEndPoint? Remote { get; set; } 22 | 23 | /// 管道处理器解码后的消息,一般就是业务消息 24 | public Object? Message { get; set; } 25 | 26 | /// 用户自定义数据 27 | public Object? UserState { get; set; } 28 | #endregion 29 | 30 | /// 获取当前事件的原始数据。避免用户错误使用Packet.Data 31 | /// 32 | public Byte[]? GetBytes() => Packet?.ToArray(); 33 | } -------------------------------------------------------------------------------- /NewLife.Core/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | FileSystem 8 | Release 9 | Any CPU 10 | netstandard2.0 11 | ..\..\Bin\ 12 | 13 | -------------------------------------------------------------------------------- /NewLife.Core/Reflection/IIndexAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Reflection 4 | { 5 | /// 6 | /// 索引器接访问口。 7 | /// 该接口用于通过名称快速访问对象属性或字段(属性优先)。 8 | /// 9 | //[Obsolete("=>IIndex")] 10 | public interface IIndexAccessor 11 | { 12 | /// 获取/设置 指定名称的属性或字段的值 13 | /// 名称 14 | /// 15 | Object this[String name] { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /NewLife.Core/Remoting/ApiAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Remoting 4 | { 5 | /// 标识Api 6 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] 7 | public class ApiAttribute : Attribute 8 | { 9 | /// 名称 10 | public String Name { get; set; } 11 | 12 | /// 实例化 13 | /// 14 | public ApiAttribute(String name) => Name = name; 15 | } 16 | } -------------------------------------------------------------------------------- /NewLife.Core/Remoting/ApiCode.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Remoting; 2 | 3 | /// Api接口响应代码 4 | public class ApiCode 5 | { 6 | /// 成功 7 | public const Int32 Ok = 0; 8 | 9 | /// 200成功。一般用于Http响应,也有部分JsonRpc使用该响应码表示成功 10 | public const Int32 Ok200 = 200; 11 | 12 | /// 未经许可。一般是指未登录 13 | public const Int32 Unauthorized = 401; 14 | 15 | /// 禁止访问。一般是只已登录但无权访问 16 | public const Int32 Forbidden = 403; 17 | 18 | /// 找不到 19 | public const Int32 NotFound = 404; 20 | 21 | /// 内部服务错误。通用错误 22 | public const Int32 InternalServerError = 500; 23 | } -------------------------------------------------------------------------------- /NewLife.Core/Remoting/ApiException.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Remoting; 2 | 3 | /// 远程调用异常 4 | public class ApiException : Exception 5 | { 6 | /// 代码 7 | public Int32 Code { get; set; } 8 | 9 | ///// 异常消息。已重载,加上错误码前缀 10 | //public override String Message => $"[{Code}]{base.Message}"; 11 | 12 | /// 实例化远程调用异常 13 | /// 14 | /// 15 | public ApiException(Int32 code, String message) : base(message) => Code = code; 16 | 17 | /// 实例化远程调用异常 18 | /// 19 | /// 20 | public ApiException(Int32 code, Exception ex) : base(ex.Message, ex) => Code = code; 21 | } -------------------------------------------------------------------------------- /NewLife.Core/Remoting/ApiHttpServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NewLife.Http; 3 | using NewLife.Net; 4 | 5 | namespace NewLife.Remoting 6 | { 7 | class ApiHttpServer : ApiNetServer 8 | { 9 | #region 属性 10 | //private String RawUrl; 11 | #endregion 12 | 13 | public ApiHttpServer() 14 | { 15 | Name = "Http"; 16 | 17 | ProtocolType = NetType.Http; 18 | } 19 | 20 | /// 初始化 21 | /// 22 | /// 23 | /// 24 | public override Boolean Init(Object config, IApiHost host) 25 | { 26 | Host = host; 27 | 28 | var uri = config as NetUri; 29 | Port = uri.Port; 30 | 31 | //RawUrl = uri + ""; 32 | 33 | // Http封包协议 34 | //Add(); 35 | Add(new HttpCodec { AllowParseHeader = true }); 36 | 37 | //host.Handler = new ApiHttpHandler { Host = host }; 38 | host.Encoder = new HttpEncoder(); 39 | 40 | return true; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /NewLife.Core/Remoting/Filters/IActionFilter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace NewLife.Remoting 5 | { 6 | /// 定义操作筛选器中使用的方法。 7 | public interface IActionFilter 8 | { 9 | /// 在执行操作方法之前调用。 10 | /// 11 | void OnActionExecuting(ControllerContext filterContext); 12 | 13 | /// 在执行操作方法后调用。 14 | /// 15 | void OnActionExecuted(ControllerContext filterContext); 16 | } 17 | } -------------------------------------------------------------------------------- /NewLife.Core/Remoting/HttpClientEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Remoting; 2 | 3 | /// Http客户端事件参数 4 | public class HttpClientEventArgs : EventArgs 5 | { 6 | /// 客户端 7 | public HttpClient Client { get; set; } = null!; 8 | } 9 | -------------------------------------------------------------------------------- /NewLife.Core/Remoting/HttpRequestEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Remoting; 2 | 3 | /// Http请求事件参数 4 | public class HttpRequestEventArgs : EventArgs 5 | { 6 | /// 客户端 7 | public HttpRequestMessage Request { get; set; } = null!; 8 | } 9 | -------------------------------------------------------------------------------- /NewLife.Core/Remoting/IApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NewLife.Remoting 8 | { 9 | /// Api接口 10 | /// 11 | /// 在基于令牌Token的无状态验证模式中,可以借助Token重写IApiHandler.Prepare,来达到同一个Token共用相同的IApiSession.Items 12 | /// 13 | public interface IApi 14 | { 15 | /// 会话 16 | IApiSession Session { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /NewLife.Core/Remoting/IApiClient.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Remoting; 2 | 3 | /// 应用接口客户端接口 4 | public interface IApiClient 5 | { 6 | /// 令牌。每次请求携带 7 | String? Token { get; set; } 8 | 9 | /// 同步调用,阻塞等待 10 | /// 服务操作 11 | /// 参数 12 | /// 13 | TResult? Invoke(String action, Object? args = null); 14 | 15 | /// 异步调用,等待返回结果 16 | /// 17 | /// 服务操作 18 | /// 参数 19 | /// 取消通知 20 | /// 21 | Task InvokeAsync(String action, Object? args = null, CancellationToken cancellationToken = default); 22 | } -------------------------------------------------------------------------------- /NewLife.Core/Remoting/IApiHost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NewLife.Log; 3 | using NewLife.Model; 4 | 5 | namespace NewLife.Remoting 6 | { 7 | /// Api主机 8 | public interface IApiHost 9 | { 10 | /// 编码器 11 | IEncoder Encoder { get; set; } 12 | 13 | /// 获取消息编码器。重载以指定不同的封包协议 14 | /// 15 | IHandler GetMessageCodec(); 16 | 17 | /// 日志 18 | ILog Log { get; set; } 19 | 20 | /// 写日志 21 | /// 22 | /// 23 | void WriteLog(String format, params Object[] args); 24 | } 25 | } -------------------------------------------------------------------------------- /NewLife.Core/Remoting/IApiServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NewLife.Log; 3 | 4 | namespace NewLife.Remoting 5 | { 6 | /// 应用接口服务器接口 7 | public interface IApiServer 8 | { 9 | /// 主机 10 | IApiHost Host { get; set; } 11 | 12 | /// 当前服务器所有会话 13 | IApiSession[] AllSessions { get; } 14 | 15 | /// 初始化 16 | /// 17 | /// 18 | /// 19 | Boolean Init(Object config, IApiHost host); 20 | 21 | /// 开始 22 | void Start(); 23 | 24 | /// 停止 25 | /// 关闭原因。便于日志分析 26 | void Stop(String reason); 27 | 28 | /// 日志 29 | ILog Log { get; set; } 30 | } 31 | } -------------------------------------------------------------------------------- /NewLife.Core/Security/AlgorithmKeyBlob.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NewLife.Security 7 | { 8 | enum AlgorithmKeyBlob 9 | { 10 | ECDH_PUBLIC_P256 = 0x314B4345, 11 | ECDH_PRIVATE_P256 = 0x324B4345, 12 | ECDH_PUBLIC_P384 = 0x334B4345, 13 | ECDH_PRIVATE_P384 = 0x344B4345, 14 | ECDH_PUBLIC_P521 = 0x354B4345, 15 | ECDH_PRIVATE_P521 = 0x364B4345, 16 | ECDH_PUBLIC_GENERIC = 0x504B4345, 17 | ECDH_PRIVATE_GENERIC = 0x564B4345, 18 | ECDSA_PUBLIC_P256 = 0x31534345, 19 | ECDSA_PRIVATE_P256 = 0x32534345, 20 | ECDSA_PUBLIC_P384 = 0x33534345, 21 | ECDSA_PRIVATE_P384 = 0x34534345, 22 | ECDSA_PUBLIC_P521 = 0x35534345, 23 | ECDSA_PRIVATE_P521 = 0x36534345, 24 | ECDSA_PUBLIC_GENERIC = 0x50444345, 25 | ECDSA_PRIVATE_GENERIC = 0x56444345, 26 | RSAPUBLIC = 0x31415352, 27 | RSAPRIVATE = 0x32415352, 28 | RSAFULLPRIVATE = 0x33415352, 29 | KEY_DATA_BLOB = 0x4D42444B 30 | } 31 | } -------------------------------------------------------------------------------- /NewLife.Core/Serialization/Binary/BinaryColor.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using System.Drawing; 3 | 4 | namespace NewLife.Serialization; 5 | 6 | /// 颜色处理器。 7 | public class BinaryColor : BinaryHandlerBase 8 | { 9 | /// 实例化 10 | public BinaryColor() => Priority = 50; 11 | 12 | /// 写入对象 13 | /// 目标对象 14 | /// 类型 15 | /// 16 | public override Boolean Write(Object? value, Type type) 17 | { 18 | if (type != typeof(Color)) return false; 19 | 20 | var color = (Color)(value ?? Color.Empty); 21 | WriteLog("WriteColor {0}", color); 22 | 23 | Host.Write(color.A); 24 | Host.Write(color.R); 25 | Host.Write(color.G); 26 | Host.Write(color.B); 27 | 28 | return true; 29 | } 30 | 31 | /// 尝试读取指定类型对象 32 | /// 33 | /// 34 | /// 35 | public override Boolean TryRead(Type type, ref Object? value) 36 | { 37 | if (type != typeof(Color)) return false; 38 | 39 | var a = Host.ReadByte(); 40 | var r = Host.ReadByte(); 41 | var g = Host.ReadByte(); 42 | var b = Host.ReadByte(); 43 | var color = Color.FromArgb(a, r, g, b); 44 | WriteLog("ReadColor {0}", color); 45 | value = color; 46 | 47 | return true; 48 | } 49 | } -------------------------------------------------------------------------------- /NewLife.Core/Serialization/BinaryCodec.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NewLife.Data; 3 | using NewLife.Model; 4 | using NewLife.Net.Handlers; 5 | 6 | namespace NewLife.Serialization 7 | { 8 | /// 二进制编码解码器 9 | public class BinaryCodec : Handler 10 | { 11 | /// 使用7位编码整数。默认true使用 12 | public Boolean EncodedInt { get; set; } = true; 13 | 14 | /// 对象转二进制 15 | /// 16 | /// 17 | /// 18 | public override Object Write(IHandlerContext context, Object message) 19 | { 20 | if (message is T entity) return Binary.FastWrite(entity, EncodedInt); 21 | 22 | return message; 23 | } 24 | 25 | /// 二进制转对象 26 | /// 27 | /// 28 | /// 29 | public override Object Read(IHandlerContext context, Object message) 30 | { 31 | if (message is Packet pk) return Binary.FastRead(pk.GetStream(), EncodedInt); 32 | 33 | return message; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /NewLife.Core/Serialization/BinaryCodec2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using NewLife.Data; 4 | using NewLife.Model; 5 | using NewLife.Net.Handlers; 6 | 7 | namespace NewLife.Serialization 8 | { 9 | /// 二进制编码解码器 10 | public class BinaryCodec2 : Handler 11 | { 12 | /// 使用7位编码整数。默认true使用 13 | public Boolean EncodedInt { get; set; } = true; 14 | 15 | /// 对象转二进制 16 | /// 17 | /// 18 | /// 19 | public override Object Write(IHandlerContext context, Object message) 20 | { 21 | if (message is IDictionary entity) return Binary.FastWrite(entity, EncodedInt); 22 | 23 | return message; 24 | } 25 | 26 | /// 二进制转对象 27 | /// 28 | /// 29 | /// 30 | public override Object Read(IHandlerContext context, Object message) 31 | { 32 | if (message is Packet pk) 33 | { 34 | //return Binary.FastRead(pk.GetStream(), EncodedInt); 35 | // 读取二进制名值对 36 | var dic = new Dictionary(); 37 | return dic; 38 | } 39 | 40 | return message; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /NewLife.Core/Serialization/Interface/AccessorAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NewLife.Serialization.Interface; 3 | 4 | namespace NewLife.Serialization 5 | { 6 | /// 成员访问特性。使用自定义逻辑序列化成员 7 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 8 | public abstract class AccessorAttribute : Attribute, IMemberAccessor 9 | { 10 | /// 从数据流中读取消息 11 | /// 序列化 12 | /// 上下文 13 | /// 是否成功 14 | public virtual Boolean Read(IFormatterX formatter, AccessorContext context) => false; 15 | 16 | /// 把消息写入到数据流中 17 | /// 序列化 18 | /// 上下文 19 | public virtual Boolean Write(IFormatterX formatter, AccessorContext context) => false; 20 | } 21 | } -------------------------------------------------------------------------------- /NewLife.Core/Serialization/Interface/AccessorContext.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace NewLife.Serialization; 4 | 5 | /// 序列化访问上下文 6 | public class AccessorContext 7 | { 8 | /// 宿主 9 | public IFormatterX? Host { get; set; } 10 | 11 | /// 对象类型 12 | public Type? Type { get; set; } 13 | 14 | /// 目标对象 15 | public Object? Value { get; set; } 16 | 17 | /// 成员 18 | public MemberInfo? Member { get; set; } 19 | 20 | /// 用户对象。存放序列化过程中使用的用户自定义对象 21 | public Object? UserState { get; set; } 22 | } -------------------------------------------------------------------------------- /NewLife.Core/Serialization/Interface/FixedStringAttribute.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Reflection; 2 | 3 | namespace NewLife.Serialization; 4 | 5 | /// 定长字符串序列化特性 6 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 7 | public class FixedStringAttribute : AccessorAttribute 8 | { 9 | /// 长度 10 | public Int32 Length { get; set; } 11 | 12 | /// 定长字符串序列化 13 | /// 14 | public FixedStringAttribute(Int32 length) => Length = length; 15 | 16 | /// 从数据流中读取消息 17 | /// 序列化 18 | /// 上下文 19 | /// 是否成功 20 | public override Boolean Read(IFormatterX formatter, AccessorContext context) 21 | { 22 | if (formatter is Binary bn && context.Value != null && context.Member != null) 23 | { 24 | var str = bn.ReadFixedString(Length); 25 | context.Value.SetValue(context.Member, str); 26 | 27 | return true; 28 | } 29 | 30 | return false; 31 | } 32 | 33 | /// 把消息写入到数据流中 34 | /// 序列化 35 | /// 上下文 36 | public override Boolean Write(IFormatterX formatter, AccessorContext context) 37 | { 38 | if (formatter is Binary bn && context.Value != null && context.Member != null) 39 | { 40 | var str = context.Value.GetValue(context.Member) as String; 41 | bn.WriteFixedString(str, Length); 42 | 43 | return true; 44 | } 45 | 46 | return false; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /NewLife.Core/Serialization/Interface/IMemberAccessor.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Serialization.Interface; 2 | 3 | /// 成员序列化访问器。接口实现者可以在这里完全自定义序列化行为 4 | public interface IMemberAccessor 5 | { 6 | /// 从数据流中读取消息 7 | /// 序列化 8 | /// 上下文 9 | /// 是否成功 10 | Boolean Read(IFormatterX formatter, AccessorContext context); 11 | 12 | /// 把消息写入到数据流中 13 | /// 序列化 14 | /// 上下文 15 | Boolean Write(IFormatterX formatter, AccessorContext context); 16 | } -------------------------------------------------------------------------------- /NewLife.Core/Serialization/Json/JsonOptions.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Serialization; 2 | 3 | /// Json序列化选项 4 | public class JsonOptions 5 | { 6 | /// 使用驼峰命名。默认false 7 | public Boolean CamelCase { get; set; } 8 | 9 | /// 忽略空值。默认false 10 | public Boolean IgnoreNullValues { get; set; } 11 | 12 | /// 忽略循环引用。遇到循环引用时写{},默认false 13 | public Boolean IgnoreCycles { get; set; } 14 | 15 | /// 缩进。默认false 16 | public Boolean WriteIndented { get; set; } 17 | 18 | /// 使用完整的时间格式。如:2022-11-29T14:13:17.8763881+08:00,默认false 19 | public Boolean FullTime { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /NewLife.Core/Serialization/JsonCodec.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NewLife.Data; 3 | using NewLife.Model; 4 | using NewLife.Net.Handlers; 5 | 6 | namespace NewLife.Serialization 7 | { 8 | /// Json编码解码器 9 | public class JsonCodec : Handler 10 | { 11 | /// 对象转Json 12 | /// 13 | /// 14 | /// 15 | public override Object Write(IHandlerContext context, Object message) 16 | { 17 | if (message is T entity) return new Packet(entity.ToJson().GetBytes()); 18 | 19 | return message; 20 | } 21 | 22 | /// Json转对象 23 | /// 24 | /// 25 | /// 26 | public override Object Read(IHandlerContext context, Object message) 27 | { 28 | if (message is Packet pk) message = pk.ToStr(); 29 | if (message is String str) return str.ToJsonEntity(); 30 | 31 | return message; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /NewLife.Core/Serialization/JsonCodec2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using NewLife.Data; 4 | using NewLife.Model; 5 | using NewLife.Net.Handlers; 6 | 7 | namespace NewLife.Serialization 8 | { 9 | /// Json编码解码器 10 | public class JsonCodec2 : Handler 11 | { 12 | /// 对象转Json 13 | /// 14 | /// 15 | /// 16 | public override Object Write(IHandlerContext context, Object message) 17 | { 18 | if (message is IDictionary entity) return new Packet(entity.ToJson().GetBytes()); 19 | 20 | return message; 21 | } 22 | 23 | /// Json转对象 24 | /// 25 | /// 26 | /// 27 | public override Object Read(IHandlerContext context, Object message) 28 | { 29 | if (message is Packet pk) message = pk.ToStr(); 30 | if (message is String str) return new JsonParser(str).Decode(); 31 | 32 | return message; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /NewLife.Core/Serialization/JsonConverter.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace NewLife.Serialization; 6 | 7 | /// Json反序列化时进行类型绑定。用于指定接口的实现类 8 | /// 9 | /// 10 | public class JsonConverter : JsonConverter where TImplementation : TService 11 | { 12 | /// 读取 13 | /// 14 | /// 15 | /// 16 | /// 17 | #if NETCOREAPP3_1 18 | public override TService Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => JsonSerializer.Deserialize(ref reader, options); 19 | #else 20 | public override TService? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => JsonSerializer.Deserialize(ref reader, options); 21 | #endif 22 | 23 | /// 写入 24 | /// 25 | /// 26 | /// 27 | public override void Write(Utf8JsonWriter writer, TService value, JsonSerializerOptions options) => JsonSerializer.Serialize(writer, value, options); 28 | } 29 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Serialization/TypeConverter.cs: -------------------------------------------------------------------------------- 1 | #if NETCOREAPP 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Text.Json; 4 | using System.Text.Json.Serialization; 5 | using NewLife.Reflection; 6 | 7 | namespace NewLife.Serialization; 8 | 9 | /// 面向Type的Json序列化转换器 10 | /// 借助字符串序列化Type.FullName 11 | public class TypeConverter : JsonConverter 12 | { 13 | /// 读取类型 14 | /// 15 | /// 16 | /// 17 | /// 18 | #if NETCOREAPP3_1 19 | public override Type Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => reader.GetString()!.GetTypeEx()!; 20 | #else 21 | public override Type? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => reader.GetString()?.GetTypeEx(); 22 | #endif 23 | 24 | /// 写入类型 25 | /// 26 | /// 27 | /// 28 | public override void Write(Utf8JsonWriter writer, Type value, JsonSerializerOptions options) => writer.WriteStringValue(value.FullName); 29 | } 30 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Stub/IsExternalInit.cs: -------------------------------------------------------------------------------- 1 | #if NETFRAMEWORK || NETSTANDARD || NETCOREAPP3_1 2 | using System.ComponentModel; 3 | 4 | namespace System.Runtime.CompilerServices; 5 | 6 | /// 保留供编译器用于跟踪元数据。 开发人员不应在源代码中使用此类。 7 | [EditorBrowsable(EditorBrowsableState.Never)] 8 | public static class IsExternalInit 9 | { 10 | } 11 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Stub/MaybeNullAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETFRAMEWORK || NETSTANDARD2_0 2 | namespace System.Diagnostics.CodeAnalysis; 3 | 4 | /// 返回可能为空 5 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] 6 | public sealed class MaybeNullAttribute : Attribute 7 | { 8 | } 9 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Stub/MaybeNullWhenAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETFRAMEWORK || NETSTANDARD2_0 2 | namespace System.Diagnostics.CodeAnalysis; 3 | 4 | /// 当返回指定值时可能为空 5 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 6 | public sealed class MaybeNullWhenAttribute : Attribute 7 | { 8 | /// 返回值 9 | public Boolean ReturnValue { get; } 10 | 11 | /// 实例化 12 | /// 13 | public MaybeNullWhenAttribute(Boolean returnValue) => ReturnValue = returnValue; 14 | } 15 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Stub/MemberNotNullAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETFRAMEWORK || NETSTANDARD || NETCOREAPP3_1 2 | namespace System.Diagnostics.CodeAnalysis; 3 | 4 | /// 执行方法后指定成员不为空 5 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] 6 | public sealed class MemberNotNullAttribute : Attribute 7 | { 8 | /// 不为空的成员 9 | public String[] Members { get; } 10 | 11 | /// 成员不为空 12 | /// 13 | public MemberNotNullAttribute(String member) => Members = [member]; 14 | 15 | /// 成员不为空 16 | /// 17 | public MemberNotNullAttribute(params String[] members) => Members = members; 18 | } 19 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Stub/MemberNotNullWhenAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETFRAMEWORK || NETSTANDARD || NETCOREAPP3_1 2 | namespace System.Diagnostics.CodeAnalysis; 3 | 4 | /// 执行方法后指定成员不为空(带条件) 5 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] 6 | public sealed class MemberNotNullWhenAttribute : Attribute 7 | { 8 | /// 返回值 9 | public Boolean ReturnValue { get; } 10 | 11 | /// 不为空的成员 12 | public String[] Members { get; } 13 | 14 | /// 成员不为空 15 | /// 16 | /// 17 | public MemberNotNullWhenAttribute(Boolean returnValue, String member) 18 | { 19 | ReturnValue = returnValue; 20 | Members = [member]; 21 | } 22 | 23 | /// 成员不为空 24 | /// 25 | /// 26 | public MemberNotNullWhenAttribute(Boolean returnValue, params String[] members) 27 | { 28 | ReturnValue = returnValue; 29 | Members = members; 30 | } 31 | } 32 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Stub/NotNullAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETFRAMEWORK || NETSTANDARD2_0 2 | namespace System.Diagnostics.CodeAnalysis; 3 | 4 | /// 不为空 5 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] 6 | public sealed class NotNullAttribute : Attribute 7 | { 8 | } 9 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Stub/NotNullIfNotNullAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETFRAMEWORK || NETSTANDARD2_0 2 | namespace System.Diagnostics.CodeAnalysis; 3 | 4 | /// 指定参数不为空时返回也不为空 5 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] 6 | public sealed class NotNullIfNotNullAttribute : Attribute 7 | { 8 | /// 指定参数 9 | public String ParameterName { get; } 10 | 11 | /// 实例化 12 | /// 13 | public NotNullIfNotNullAttribute(String parameterName) => ParameterName = parameterName; 14 | } 15 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Stub/NotNullWhenAttribute.cs: -------------------------------------------------------------------------------- 1 | #if NETFRAMEWORK || NETSTANDARD2_0 2 | namespace System.Diagnostics.CodeAnalysis; 3 | 4 | /// 指定在方法返回 ReturnValue 时,即使相应的类型允许,参数也不会为 null。 5 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 6 | public sealed class NotNullWhenAttribute : Attribute 7 | { 8 | /// 获取返回值条件。 9 | public Boolean ReturnValue { get; } 10 | 11 | /// 使用指定的返回值条件初始化属性。 12 | /// 13 | public NotNullWhenAttribute(Boolean returnValue) => ReturnValue = returnValue; 14 | } 15 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Stub/ScriptIgnoreAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace System.Web.Script.Serialization 6 | { 7 | /// 忽略Json序列化 8 | public class ScriptIgnoreAttribute : Attribute { } 9 | } -------------------------------------------------------------------------------- /NewLife.Core/Threading/ITimer.cs: -------------------------------------------------------------------------------- 1 | namespace System.Threading; 2 | 3 | #if NETFRAMEWORK || NETSTANDARD || NETCOREAPP3_1 || NET5_0 || NET6_0 || NET7_0 4 | /// 表示可以更改其到期时间和时间段的计时器。 5 | public interface ITimer : IDisposable 6 | { 7 | /// 更改计时器的启动时间和方法调用之间的时间间隔,使用 TimeSpan 值度量时间间隔。 8 | /// 一个 TimeSpan,表示在调用构造 ITimer 时指定的回调方法之前的延迟时间量。 指定 InfiniteTimeSpan 可防止重新启动计时器。 指定 Zero 可立即重新启动计时器。 9 | /// 构造 Timer 时指定的回调方法调用之间的时间间隔。 指定 InfiniteTimeSpan 可以禁用定期终止。 10 | /// 11 | Boolean Change(TimeSpan dueTime, TimeSpan period); 12 | } 13 | #endif -------------------------------------------------------------------------------- /NewLife.Core/Threading/TaskEx.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.Contracts; 2 | namespace System.Threading.Tasks; 3 | 4 | #if NET45 5 | /// 任务扩展 6 | public static class TaskEx 7 | { 8 | private static readonly Task s_preCompletedTask = Task.FromResult(false); 9 | /// 已完成任务 10 | public static Task CompletedTask => s_preCompletedTask; 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /NewLife.Core/Web/OAuth/QQClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace NewLife.Web.OAuth 5 | { 6 | /// 身份验证提供者 7 | public class QQClient : OAuthClient 8 | { 9 | /// 实例化 10 | public QQClient() 11 | { 12 | Server = "https://graph.qq.com/oauth2.0/"; 13 | 14 | AuthUrl = "authorize?response_type={response_type}&client_id={key}&redirect_uri={redirect}&state={state}&scope={scope}"; 15 | AccessUrl = "token?grant_type=authorization_code&client_id={key}&client_secret={secret}&code={code}&state={state}&redirect_uri={redirect}"; 16 | OpenIDUrl = "me?access_token={token}"; 17 | UserUrl = "https://graph.qq.com/user/get_user_info?access_token={token}&oauth_consumer_key={key}&openid={openid}"; 18 | } 19 | 20 | /// 从响应数据中获取信息 21 | /// 22 | protected override void OnGetInfo(IDictionary dic) 23 | { 24 | base.OnGetInfo(dic); 25 | 26 | if (dic.ContainsKey("nickname")) NickName = dic["nickname"].Trim(); 27 | if (dic.ContainsKey("client_id")) UserID = dic["client_id"].ToLong(); 28 | 29 | // 从大到小找头像 30 | var avs = "figureurl_qq_2,figureurl_qq_1,figureurl_2,figureurl_1,figureurl".Split(","); 31 | foreach (var item in avs) 32 | { 33 | if (dic.TryGetValue(item, out var av) && !av.IsNullOrEmpty()) 34 | { 35 | Avatar = av.Trim(); 36 | break; 37 | } 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /NewLife.Core/Web/OAuth/TaobaoClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace NewLife.Web.OAuth 5 | { 6 | /// 淘宝身份验证提供者 7 | public class TaobaoClient : OAuthClient 8 | { 9 | /// 实例化 10 | public TaobaoClient() 11 | { 12 | var url = "https://oauth.taobao.com/"; 13 | 14 | AuthUrl = url + "authorize?response_type={response_type}&client_id={key}&redirect_uri={redirect}&state={state}&scope={scope}"; 15 | AccessUrl = url + "token?grant_type=authorization_code&client_id={key}&client_secret={secret}&code={code}&state={state}&redirect_uri={redirect}"; 16 | //UserUrl = "https://openapi.baidu.com/rest/2.0/passport/users/getLoggedInUser?access_token={token}"; 17 | LogoutUrl = url + "logoff?client_id={key}&view=web"; 18 | } 19 | 20 | /// 从响应数据中获取信息 21 | /// 22 | protected override void OnGetInfo(IDictionary dic) 23 | { 24 | base.OnGetInfo(dic); 25 | 26 | if (dic.ContainsKey("taobao_user_id")) UserID = dic["taobao_user_id"].Trim('\"').ToLong(); 27 | if (dic.ContainsKey("taobao_user_nick")) UserName = dic["taobao_user_nick"].Trim(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /NewLife.Core/Web/OAuth/WeixinClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace NewLife.Web.OAuth 5 | { 6 | /// 身份验证提供者 7 | public class WeixinClient : OAuthClient 8 | { 9 | /// 实例化 10 | public WeixinClient() 11 | { 12 | } 13 | 14 | /// 从响应数据中获取信息 15 | /// 16 | protected override void OnGetInfo(IDictionary dic) 17 | { 18 | base.OnGetInfo(dic); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /NewLife.Core/Web/TokenModel.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace NewLife.Web; 4 | 5 | /// 访问令牌模型 6 | public class TokenModel 7 | { 8 | /// 访问令牌 9 | [DataMember(Name = "access_token")] 10 | public String? AccessToken { get; set; } 11 | 12 | /// 令牌类型 13 | [DataMember(Name = "token_type")] 14 | public String? TokenType { get; set; } 15 | 16 | /// 过期时间。秒 17 | [DataMember(Name = "expire_in")] 18 | public Int32 ExpireIn { get; set; } 19 | 20 | /// 刷新令牌 21 | [DataMember(Name = "refresh_token")] 22 | public String? RefreshToken { get; set; } 23 | } -------------------------------------------------------------------------------- /NewLife.Core/Xml/XmlConfigFileAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace NewLife.Xml; 2 | 3 | /// Xml配置文件特性 4 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 5 | public class XmlConfigFileAttribute : Attribute 6 | { 7 | /// 配置文件名 8 | public String FileName { get; set; } 9 | 10 | /// 重新加载时间。单位:毫秒 11 | public Int32 ReloadTime { get; set; } 12 | 13 | /// 指定配置文件名 14 | /// 15 | public XmlConfigFileAttribute(String fileName) => FileName = fileName; 16 | 17 | /// 指定配置文件名和重新加载时间(毫秒) 18 | /// 19 | /// 20 | public XmlConfigFileAttribute(String fileName, Int32 reloadTime) 21 | { 22 | FileName = fileName; 23 | ReloadTime = reloadTime; 24 | } 25 | } -------------------------------------------------------------------------------- /NewLife.Core/Yun/Driving.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Yun 4 | { 5 | /// 驾车距离和时间 6 | public class Driving 7 | { 8 | /// 距离。单位米 9 | public Int32 Distance { get; set; } 10 | 11 | /// 路线耗时。单位秒 12 | public Int32 Duration { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Assets/AboutAssets.txt: -------------------------------------------------------------------------------- 1 | Any raw assets you want to be deployed with your application can be placed in 2 | this directory (and child directories) and given a Build Action of "AndroidAsset". 3 | 4 | These files will be deployed with your package and will be accessible using Android's 5 | AssetManager, like this: 6 | 7 | public class ReadAsset : Activity 8 | { 9 | protected override void OnCreate (Bundle bundle) 10 | { 11 | base.OnCreate (bundle); 12 | 13 | InputStream input = Assets.Open ("my_asset.txt"); 14 | } 15 | } 16 | 17 | Additionally, some Android functions will automatically load asset files: 18 | 19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); 20 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using Android.App; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("MobileApp.Android")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("MobileApp.Android")] 14 | [assembly: AssemblyCopyright("Copyright © 2014")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: ComVisible(false)] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.*")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | 32 | // Add some common permissions, these can be removed if not needed 33 | [assembly: UsesPermission(Android.Manifest.Permission.Internet)] 34 | [assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)] 35 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/drawable/xamarin_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.Android/Resources/drawable/xamarin_logo.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/layout/Tabbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/layout/Toolbar.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-anydpi-v26/icon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-anydpi-v26/icon_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.Android/Resources/mipmap-hdpi/icon.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-hdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.Android/Resources/mipmap-hdpi/launcher_foreground.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.Android/Resources/mipmap-mdpi/icon.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-mdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.Android/Resources/mipmap-mdpi/launcher_foreground.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.Android/Resources/mipmap-xhdpi/icon.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-xhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.Android/Resources/mipmap-xhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.Android/Resources/mipmap-xxhdpi/icon.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-xxhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.Android/Resources/mipmap-xxhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.Android/Resources/mipmap-xxxhdpi/icon.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | #3F51B5 5 | #303F9F 6 | #FF4081 7 | 8 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.Android/Resources/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 26 | 27 | 30 | 31 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | using Foundation; 6 | using UIKit; 7 | 8 | namespace MobileApp.iOS 9 | { 10 | // The UIApplicationDelegate for the application. This class is responsible for launching the 11 | // User Interface of the application, as well as listening (and optionally responding) to 12 | // application events from iOS. 13 | [Register("AppDelegate")] 14 | public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate 15 | { 16 | // 17 | // This method is invoked when the application has loaded and is ready to run. In this 18 | // method you should instantiate the window, load the UI into it and then make the window 19 | // visible. 20 | // 21 | // You have 17 seconds to return from this method, or iOS will terminate your application. 22 | // 23 | public override bool FinishedLaunching(UIApplication app, NSDictionary options) 24 | { 25 | global::Xamarin.Forms.Forms.Init(); 26 | LoadApplication(new App()); 27 | 28 | return base.FinishedLaunching(app, options); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon20.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon29.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon40.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon80.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Entitlements.plist: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIDeviceFamily 6 | 7 | 1 8 | 2 9 | 10 | UISupportedInterfaceOrientations 11 | 12 | UIInterfaceOrientationPortrait 13 | UIInterfaceOrientationLandscapeLeft 14 | UIInterfaceOrientationLandscapeRight 15 | 16 | UISupportedInterfaceOrientations~ipad 17 | 18 | UIInterfaceOrientationPortrait 19 | UIInterfaceOrientationPortraitUpsideDown 20 | UIInterfaceOrientationLandscapeLeft 21 | UIInterfaceOrientationLandscapeRight 22 | 23 | MinimumOSVersion 24 | 8.0 25 | CFBundleDisplayName 26 | MobileApp 27 | CFBundleIdentifier 28 | com.companyname.MobileApp 29 | CFBundleVersion 30 | 1.0 31 | UILaunchStoryboardName 32 | LaunchScreen 33 | CFBundleName 34 | MobileApp 35 | XSAppIconAssets 36 | Assets.xcassets/AppIcon.appiconset 37 | 38 | 39 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | using Foundation; 6 | using UIKit; 7 | 8 | namespace MobileApp.iOS 9 | { 10 | public class Application 11 | { 12 | // This is the main entry point of the application. 13 | static void Main(string[] args) 14 | { 15 | // if you want to use a different Application Delegate class from "AppDelegate" 16 | // you can specify it here. 17 | UIApplication.Main(args, null, typeof(AppDelegate)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MobileApp.iOS")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MobileApp.iOS")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("72bdc44f-c588-44f3-b6df-9aace7daafdd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/Default-568h@2x.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/Default-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/Default-Portrait.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/Default-Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/Default-Portrait@2x.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/Default.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/Default@2x.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/tab_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/tab_about.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/tab_about@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/tab_about@2x.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/tab_about@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/tab_about@3x.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/tab_feed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/tab_feed.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/tab_feed@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/tab_feed@2x.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/tab_feed@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/tab_feed@3x.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/xamarin_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/xamarin_logo.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/xamarin_logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/xamarin_logo@2x.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp.iOS/Resources/xamarin_logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Samples/MobileApp/MobileApp.iOS/Resources/xamarin_logo@3x.png -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/App.xaml: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | 10 | 11 | 12 | #2196F3 13 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using Xamarin.Forms.Xaml; 2 | 3 | [assembly: XamlCompilation(XamlCompilationOptions.Compile)] -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/MobileApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.1 4 | true 5 | 1.0 6 | $([System.DateTime]::Now.ToString(`yyyy.MMdd`)) 7 | $(VersionPrefix).$(VersionSuffix) 8 | $(Version) 9 | $(VersionPrefix).* 10 | false 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/Models/HomeMenuItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace MobileApp.Models 6 | { 7 | public enum MenuItemType 8 | { 9 | Browse, 10 | About 11 | } 12 | public class HomeMenuItem 13 | { 14 | public MenuItemType Id { get; set; } 15 | 16 | public string Title { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/Models/Item.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MobileApp.Models 4 | { 5 | public class Item 6 | { 7 | public string Id { get; set; } 8 | public string Text { get; set; } 9 | public string Description { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/Services/IDataStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | namespace MobileApp.Services 6 | { 7 | public interface IDataStore 8 | { 9 | Task AddItemAsync(T item); 10 | Task UpdateItemAsync(T item); 11 | Task DeleteItemAsync(string id); 12 | Task GetItemAsync(string id); 13 | Task> GetItemsAsync(bool forceRefresh = false); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/ViewModels/AboutViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Input; 3 | using Xamarin.Essentials; 4 | using Xamarin.Forms; 5 | 6 | namespace MobileApp.ViewModels 7 | { 8 | public class AboutViewModel : BaseViewModel 9 | { 10 | public AboutViewModel() 11 | { 12 | Title = "关于"; 13 | 14 | OpenWebCommand = new Command(() => Launcher.OpenAsync(new Uri("https://newlifex.com"))); 15 | } 16 | 17 | public ICommand OpenWebCommand { get; } 18 | } 19 | } -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/ViewModels/ItemDetailViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using MobileApp.Models; 4 | 5 | namespace MobileApp.ViewModels 6 | { 7 | public class ItemDetailViewModel : BaseViewModel 8 | { 9 | public Item Item { get; set; } 10 | public ItemDetailViewModel(Item item = null) 11 | { 12 | Title = item?.Text; 13 | Item = item; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/Views/AboutPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using Xamarin.Forms; 4 | using Xamarin.Forms.Xaml; 5 | 6 | namespace MobileApp.Views 7 | { 8 | // Learn more about making custom code visible in the Xamarin.Forms previewer 9 | // by visiting https://aka.ms/xamarinforms-previewer 10 | [DesignTimeVisible(false)] 11 | public partial class AboutPage : ContentPage 12 | { 13 | public AboutPage() 14 | { 15 | InitializeComponent(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/Views/ItemDetailPage.xaml: -------------------------------------------------------------------------------- 1 |  2 | 9 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/Views/ItemDetailPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using Xamarin.Forms; 4 | using Xamarin.Forms.Xaml; 5 | 6 | using MobileApp.Models; 7 | using MobileApp.ViewModels; 8 | using NewLife; 9 | using NewLife.Serialization; 10 | 11 | namespace MobileApp.Views 12 | { 13 | // Learn more about making custom code visible in the Xamarin.Forms previewer 14 | // by visiting https://aka.ms/xamarinforms-previewer 15 | [DesignTimeVisible(false)] 16 | public partial class ItemDetailPage : ContentPage 17 | { 18 | ItemDetailViewModel viewModel; 19 | 20 | public ItemDetailPage(ItemDetailViewModel viewModel) 21 | { 22 | InitializeComponent(); 23 | 24 | BindingContext = this.viewModel = viewModel; 25 | } 26 | 27 | public ItemDetailPage() 28 | { 29 | InitializeComponent(); 30 | 31 | var item = new Item 32 | { 33 | Text = "Item 1", 34 | Description = "This is an item description." 35 | }; 36 | 37 | viewModel = new ItemDetailViewModel(item); 38 | BindingContext = viewModel; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/Views/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/Views/MenuPage.xaml: -------------------------------------------------------------------------------- 1 |  2 | 9 | 10 | 11 | 13 | 14 | 15 | Item 1 16 | Item 2 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/Views/MenuPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using MobileApp.Models; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using Xamarin.Forms; 6 | using Xamarin.Forms.Xaml; 7 | 8 | namespace MobileApp.Views 9 | { 10 | // Learn more about making custom code visible in the Xamarin.Forms previewer 11 | // by visiting https://aka.ms/xamarinforms-previewer 12 | [DesignTimeVisible(false)] 13 | public partial class MenuPage : ContentPage 14 | { 15 | MainPage RootPage { get => Application.Current.MainPage as MainPage; } 16 | List menuItems; 17 | public MenuPage() 18 | { 19 | InitializeComponent(); 20 | 21 | menuItems = new List 22 | { 23 | new HomeMenuItem {Id = MenuItemType.Browse, Title="浏览" }, 24 | new HomeMenuItem {Id = MenuItemType.About, Title="关于" } 25 | }; 26 | 27 | ListViewMenu.ItemsSource = menuItems; 28 | 29 | ListViewMenu.SelectedItem = menuItems[0]; 30 | ListViewMenu.ItemSelected += async (sender, e) => 31 | { 32 | if (e.SelectedItem == null) 33 | return; 34 | 35 | var id = (int)((HomeMenuItem)e.SelectedItem).Id; 36 | await RootPage.NavigateFromMenu(id); 37 | }; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/Views/NewItemPage.xaml: -------------------------------------------------------------------------------- 1 |  2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Samples/MobileApp/MobileApp/Views/NewItemPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using Xamarin.Forms; 5 | using Xamarin.Forms.Xaml; 6 | 7 | using MobileApp.Models; 8 | 9 | namespace MobileApp.Views 10 | { 11 | // Learn more about making custom code visible in the Xamarin.Forms previewer 12 | // by visiting https://aka.ms/xamarinforms-previewer 13 | [DesignTimeVisible(false)] 14 | public partial class NewItemPage : ContentPage 15 | { 16 | public Item Item { get; set; } 17 | 18 | public NewItemPage() 19 | { 20 | InitializeComponent(); 21 | 22 | Item = new Item 23 | { 24 | Text = "Item name", 25 | Description = "This is an item description." 26 | }; 27 | 28 | BindingContext = this; 29 | } 30 | 31 | async void Save_Clicked(object sender, EventArgs e) 32 | { 33 | MessagingCenter.Send(this, "AddItem", Item); 34 | await Navigation.PopModalAsync(); 35 | } 36 | 37 | async void Cancel_Clicked(object sender, EventArgs e) 38 | { 39 | await Navigation.PopModalAsync(); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Samples/Zero.Desktop/ClientSetting.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using NewLife; 3 | using NewLife.Configuration; 4 | using NewLife.Remoting.Clients; 5 | 6 | namespace Zero.Desktop; 7 | 8 | [Config("ClientSetting")] 9 | public class ClientSetting : Config, IClientSetting 10 | { 11 | #region 属性 12 | /// 语音提示。默认true 13 | [Description("语音提示。默认true")] 14 | public Boolean SpeechTip { get; set; } = true; 15 | 16 | /// 证书 17 | [Description("证书")] 18 | public String Code { get; set; } 19 | 20 | /// 密钥 21 | [Description("密钥")] 22 | public String Secret { get; set; } 23 | 24 | /// 服务地址端口。默认为空,子网内自动发现 25 | [Description("服务地址端口。默认为空,子网内自动发现")] 26 | public String Server { get; set; } = ""; 27 | #endregion 28 | 29 | #region 加载/保存 30 | protected override void OnLoaded() 31 | { 32 | if (Server.IsNullOrEmpty()) Server = "http://s.newlifex.com:6600"; 33 | 34 | base.OnLoaded(); 35 | } 36 | #endregion 37 | } -------------------------------------------------------------------------------- /Samples/Zero.Desktop/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | //"StarServer": "http://s.newlifex.com:6600", 11 | //"RedisCache": "server=127.0.0.1:6379;password=;db=3", 12 | //"RedisQueue": "server=127.0.0.1:6379;password=;db=5", 13 | "ConnectionStrings": { 14 | "Membership": "Data Source=..\\Data\\Membership.db;Provider=SQLite", 15 | "Log": "Data Source=..\\Data\\Log.db;Provider=SQLite", 16 | "Zero": "Data Source=..\\Data\\Zero.db;Provider=SQLite" 17 | 18 | // 各种数据库连接字符串模版,连接名Zero对应Zero.Data/Projects/Model.xml中的ConnName 19 | //"Zero": "Server=.;Port=3306;Database=zero;Uid=root;Pwd=root;Provider=MySql", 20 | //"Zero": "Data Source=.;Initial Catalog=zero;user=sa;password=sa;Provider=SqlServer", 21 | //"Zero": "Server=.;Database=zero;Uid=root;Pwd=root;Provider=PostgreSql", 22 | //"Zero": "Data Source=Tcp://127.0.0.1/ORCL;User Id=scott;Password=tiger;Provider=Oracle" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Samples/Zero.EchoServer/EchoNetServer.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Net; 2 | 3 | namespace Zero.EchoServer; 4 | 5 | /// 定义服务端,用于管理所有网络会话 6 | class EchoNetServer : NetServer 7 | { 8 | } 9 | 10 | /// 定义会话。每一个远程连接唯一对应一个网络会话,再次重复收发信息 11 | class EchoSession : NetSession 12 | { 13 | /// 收到客户端数据 14 | /// 15 | protected override void OnReceive(ReceivedEventArgs e) 16 | { 17 | if (e.Packet.Length == 0) return; 18 | 19 | // 把收到的数据发回去 20 | Send(e.Packet); 21 | } 22 | } -------------------------------------------------------------------------------- /Samples/Zero.EchoServer/Program.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Log; 2 | using NewLife.Model; 3 | using Stardust; 4 | using Zero.EchoServer; 5 | 6 | // 启用控制台日志,拦截所有异常 7 | XTrace.UseConsole(); 8 | 9 | var services = ObjectContainer.Current; 10 | 11 | // 配置星尘。自动读取配置文件 config/star.config 中的服务器地址、应用标识、密钥 12 | var star = services.AddStardust(); 13 | 14 | var provider = services.BuildServiceProvider(); 15 | 16 | // 实例化网络服务端,指定端口,同时在Tcp/Udp/IPv4/IPv6上监听 17 | var server = new EchoNetServer 18 | { 19 | Port = 7777, 20 | ServiceProvider = provider, 21 | Name = "回声服务端", 22 | 23 | StatPeriod = 10, 24 | Log = XTrace.Log, 25 | Tracer = star?.Tracer, 26 | 27 | #if DEBUG 28 | SessionLog = XTrace.Log, 29 | #endif 30 | }; 31 | 32 | // 启动网络服务,监听端口,所有逻辑将在 EchoSession 中处理 33 | server.Start(); 34 | XTrace.WriteLine("服务端启动完成!"); 35 | 36 | // 注册到星尘,非必须 37 | star?.Service?.Register("EchoServer", () => $"tcp://*:{server.Port},udp://*:{server.Port}"); 38 | 39 | // 阻塞,等待友好退出 40 | var host = services.BuildHost(); 41 | await host.RunAsync(); 42 | server.Stop("stop"); 43 | -------------------------------------------------------------------------------- /Samples/Zero.EchoServer/Zero.EchoServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | 回声服务器 7 | 网络回声服务端,把收到的数据原样发回去,用于网络性能压测 8 | 新生命开发团队 9 | ©2002-2025 NewLife 10 | 1.0 11 | $([System.DateTime]::Now.ToString(`yyyy.MMdd`)) 12 | $(VersionPrefix).$(VersionSuffix) 13 | $(Version) 14 | $(VersionPrefix).* 15 | false 16 | ..\..\Bin\EchoServer 17 | false 18 | enable 19 | latest 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Samples/Zero.EchoServer/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | //"StarServer": "http://s.newlifex.com:6600" 11 | } 12 | -------------------------------------------------------------------------------- /Samples/Zero.HttpServer/MyHttpHandler.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Http; 2 | 3 | namespace Zero.HttpServer; 4 | 5 | /// 自定义控制器。包含多个服务 6 | internal class MyHttpHandler : IHttpHandler 7 | { 8 | public void ProcessRequest(IHttpContext context) 9 | { 10 | // 获取请求参数 11 | var name = context.Parameters["name"]; 12 | 13 | var html = $"

你好,{name}

"; 14 | 15 | // 支持文件上传 16 | var files = context.Request.Files; 17 | if (files != null && files.Length > 0) 18 | { 19 | foreach (var file in files) 20 | { 21 | file.SaveToFile(); 22 | html += $"
文件:{file.FileName} 大小:{file.Length} 类型:{file.ContentType}"; 23 | } 24 | } 25 | 26 | // 设置响应结果 27 | context.Response.SetResult(html); 28 | } 29 | } -------------------------------------------------------------------------------- /Samples/Zero.HttpServer/Zero.HttpServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | Http服务器 7 | 轻量级Http服务器,支持WebSocket,可用于追求简单Http服务的场景,例如暴露硬件控制为Http接口,如打印组件 8 | 新生命开发团队 9 | ©2002-2025 NewLife 10 | 1.0 11 | $([System.DateTime]::Now.ToString(`yyyy.MMdd`)) 12 | $(VersionPrefix).$(VersionSuffix) 13 | $(Version) 14 | $(VersionPrefix).* 15 | false 16 | ..\..\Bin\HttpServer 17 | false 18 | enable 19 | latest 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Samples/Zero.HttpServer/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | //"StarServer": "http://s.newlifex.com:6600", 11 | //"RedisCache": "server=127.0.0.1:6379;password=;db=3", 12 | "ConnectionStrings": { 13 | "Zero": "Data Source=..\\Data\\Zero.db;Provider=SQLite" 14 | 15 | // 各种数据库连接字符串模版,连接名Zero对应Zero.Data/Projects/Model.xml中的ConnName 16 | //"Zero": "Server=.;Port=3306;Database=zero;Uid=root;Pwd=root;Provider=MySql", 17 | //"Zero": "Data Source=.;Initial Catalog=zero;user=sa;password=sa;Provider=SqlServer", 18 | //"Zero": "Server=.;Database=zero;Uid=root;Pwd=root;Provider=PostgreSql", 19 | //"Zero": "Data Source=Tcp://127.0.0.1/ORCL;User Id=scott;Password=tiger;Provider=Oracle" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Samples/Zero.Server/Handlers/IMsgHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Zero.TcpServer.Handlers 8 | { 9 | internal class IMsgHandler 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Samples/Zero.Server/Handlers/MyHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Zero.TcpServer.Handlers 8 | { 9 | internal class MyHandler : IMsgHandler 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Samples/Zero.Server/Zero.Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | 网络服务器 7 | 高性能网络服务器,单机最高400万连接,可用于建立各种协议的网络服务器 8 | 新生命开发团队 9 | ©2002-2025 NewLife 10 | 1.0 11 | $([System.DateTime]::Now.ToString(`yyyy.MMdd`)) 12 | $(VersionPrefix).$(VersionSuffix) 13 | $(Version) 14 | $(VersionPrefix).* 15 | false 16 | ..\..\Bin\Server 17 | false 18 | enable 19 | latest 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Samples/Zero.Server/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | //"StarServer": "http://s.newlifex.com:6600", 11 | //"RedisCache": "server=127.0.0.1:6379;password=;db=3", 12 | "ConnectionStrings": { 13 | "Zero": "Data Source=..\\Data\\Zero.db;Provider=SQLite" 14 | 15 | // 各种数据库连接字符串模版,连接名Zero对应Zero.Data/Projects/Model.xml中的ConnName 16 | //"Zero": "Server=.;Port=3306;Database=zero;Uid=root;Pwd=root;Provider=MySql", 17 | //"Zero": "Data Source=.;Initial Catalog=zero;user=sa;password=sa;Provider=SqlServer", 18 | //"Zero": "Server=.;Database=zero;Uid=root;Pwd=root;Provider=PostgreSql", 19 | //"Zero": "Data Source=Tcp://127.0.0.1/ORCL;User Id=scott;Password=tiger;Provider=Oracle" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Test/BigInteger.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/Test/BigInteger.cs -------------------------------------------------------------------------------- /Test/ConfigTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using NewLife.Configuration; 7 | 8 | namespace Test 9 | { 10 | public class ConfigTest : Config 11 | { 12 | public List Names { get; set; } 13 | 14 | public String Sex { get; set; } 15 | 16 | public List xyf { get; set; } 17 | } 18 | 19 | public class XYF 20 | { 21 | public String name { get; set; } 22 | 23 | //public List gradu { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Test/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | FileSystem 8 | Release 9 | Any CPU 10 | net7.0 11 | ..\Bin\Test\publish\win-x64\ 12 | false 13 | win-x64 14 | true 15 | false 16 | 17 | -------------------------------------------------------------------------------- /Test/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Test": { 4 | "commandName": "Project", 5 | "environmentVariables": { 6 | "ASPNETCORE_ENVIRONMENT": "Development" 7 | } 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Test/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Url": "https://newlifex.com/", 3 | "ConnectionStrings": { 4 | "MySQL.AppSettings": { 5 | "connectionString": /*中间注释*/ "Server=.;Port=3306;Database=mysql;Uid=MySQL.default;Pwd=;", 6 | "providerName": "MySql.Data.MySqlClient" 7 | // 不支持放在最后的注释,链接中的双斜杠被当成注释 8 | // 独立一行注释 9 | }, 10 | "sqlserver": { 11 | "connectionString": "Server=127.0.0.1;Database=Membership;Uid=root;Pwd=root;", 12 | "providerName": "SqlServer" 13 | }, 14 | "MySQL.AppSettings.default": { 15 | /*"connectionString": "Server=.;Port=3306;Database=mysql;Uid=MySQL.default;Pwd=;",*/ 16 | /*"providerName": "MySql.Data.MySqlClient"*/ 17 | }, 18 | "TDengine": { 19 | "connectionString": "Server=gz01.newlifex.com;Port=6030;Database=db;user=root;password=taosdata", 20 | "providerName": "TDengine" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Test/form.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 表单提交 7 | 8 | 9 |

用户信息

10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 | 25 | -------------------------------------------------------------------------------- /Test2/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Test2/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using NewLife.Log; 4 | using NewLife.Threading; 5 | using NewLife; 6 | 7 | namespace Test2 8 | { 9 | internal class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | XTrace.UseConsole(); 14 | 15 | TimerScheduler.Default.Log = XTrace.Log; 16 | 17 | while (true) 18 | { 19 | var sw = Stopwatch.StartNew(); 20 | #if !DEBUG 21 | try 22 | { 23 | #endif 24 | Test1(); 25 | #if !DEBUG 26 | } 27 | catch (Exception ex) 28 | { 29 | XTrace.WriteException(ex?.GetTrue()); 30 | } 31 | #endif 32 | 33 | sw.Stop(); 34 | Console.WriteLine("OK! 耗时 {0}", sw.Elapsed); 35 | //Thread.Sleep(5000); 36 | GC.Collect(); 37 | GC.WaitForPendingFinalizers(); 38 | var key = Console.ReadKey(true); 39 | if (key.Key != ConsoleKey.C) break; 40 | } 41 | } 42 | 43 | static void Test1() 44 | { 45 | var str = $"{DateTime.Now:yyyy}年,学无先后达者为师!"; 46 | str.SpeakAsync(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Test2/Test2.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net4.5 5 | 9.0 6 | $([System.DateTime]::Now.ToString(`yyyy.MMdd`)) 7 | $(VersionPrefix).$(VersionSuffix) 8 | $(Version) 9 | $(VersionPrefix).* 10 | false 11 | ..\Bin\Test2 12 | false 13 | latest 14 | 1701;1702;NU5104;NETSDK1138;CS7035 15 | 16 | 17 | $(DefineConstants);DEBUG 18 | full 19 | false 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /XUnitTest.Core/Caching/MemoryQueueTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using NewLife.Caching; 6 | using NewLife.Log; 7 | using Xunit; 8 | 9 | namespace XUnitTest.Caching; 10 | 11 | public class MemoryQueueTests 12 | { 13 | [Fact] 14 | public async void Test1() 15 | { 16 | XTrace.WriteLine("MemoryQueueTests.Test1"); 17 | 18 | var q = new MemoryQueue(); 19 | 20 | Assert.True(q.IsEmpty); 21 | Assert.Equal(0, q.Count); 22 | 23 | q.Add("test"); 24 | q.Add("newlife", "stone"); 25 | 26 | Assert.False(q.IsEmpty); 27 | Assert.Equal(3, q.Count); 28 | 29 | var s1 = q.TakeOne(); 30 | Assert.Equal("test", s1); 31 | 32 | var ss = q.Take(3).ToArray(); 33 | Assert.Equal(2, ss.Length); 34 | 35 | XTrace.WriteLine("begin TokeOneAsync"); 36 | ThreadPool.QueueUserWorkItem(s => 37 | { 38 | Thread.Sleep(1100); 39 | XTrace.WriteLine("add message"); 40 | q.Add("delay"); 41 | }); 42 | 43 | var s2 = await q.TakeOneAsync(15, default); 44 | XTrace.WriteLine("end TokeOneAsync"); 45 | Assert.Equal("delay", s2); 46 | } 47 | } -------------------------------------------------------------------------------- /XUnitTest.Core/Collections/CollectionHelperTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Xunit; 5 | 6 | namespace XUnitTest.Collections; 7 | 8 | public class CollectionHelperTests 9 | { 10 | [Fact] 11 | public void ToArrayTest() 12 | { 13 | var vs = new[] { 12, 34, 56, 78, 90 }; 14 | var list = new List(vs); 15 | var list2 = list as IList; 16 | 17 | var vs2 = list2.ToArray(); 18 | Assert.Equal(vs.Length, vs2.Length); 19 | Assert.Equal(vs[0], vs2[0]); 20 | Assert.Equal(vs[1], vs2[1]); 21 | Assert.Equal(vs[2], vs2[2]); 22 | Assert.Equal(vs[3], vs2[3]); 23 | Assert.Equal(vs[4], vs2[4]); 24 | 25 | //var vs3 = list2.ToArray(2); 26 | //Assert.Equal(vs.Length + 2, vs3.Length); 27 | //Assert.Equal(vs[0], vs3[2]); 28 | //Assert.Equal(vs[1], vs3[3]); 29 | //Assert.Equal(vs[2], vs3[4]); 30 | //Assert.Equal(vs[3], vs3[5]); 31 | //Assert.Equal(vs[4], vs3[6]); 32 | } 33 | 34 | [Fact] 35 | public void CheckNullable() 36 | { 37 | var dic = new Dictionary() 38 | { 39 | ["a"] = "a", 40 | ["b"] = null, 41 | ["c"] = "c" 42 | }; 43 | 44 | var rs = dic is IDictionary; 45 | Assert.True(rs); 46 | 47 | rs = dic is IDictionary; 48 | Assert.True(rs); 49 | } 50 | } -------------------------------------------------------------------------------- /XUnitTest.Core/Common/LockTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NewLife.Log; 3 | using Xunit; 4 | 5 | namespace XUnitTest.Common 6 | { 7 | public class LockTests 8 | { 9 | [Fact(DisplayName = "测试lock是否阻塞本线程")] 10 | public void TestLock() 11 | { 12 | lock (_lock) 13 | { 14 | Test(3); 15 | } 16 | } 17 | 18 | private Object _lock = new Object(); 19 | void Test(Int32 n) 20 | { 21 | // lock并不会阻塞本线程,同一个线程第二次lock同一个对象时,直接进去 22 | XTrace.WriteLine("LockTestA {0}", n); 23 | lock (_lock) 24 | { 25 | XTrace.WriteLine("LockTestB {0}", n); 26 | if (n > 1) Test(n - 1); 27 | XTrace.WriteLine("LockTestC {0}", n); 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /XUnitTest.Core/Common/SysConfigTest.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Common; 2 | using Xunit; 3 | 4 | namespace XUnitTest.Common; 5 | 6 | public class SysConfigTest 7 | { 8 | [Fact(DisplayName = "系统名称")] 9 | public void DisplayNameTest() 10 | { 11 | var asm = SysConfig.SysAssembly; 12 | Assert.NotNull(asm); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /XUnitTest.Core/Data/GeoHashTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NewLife.Data; 3 | using Xunit; 4 | 5 | namespace XUnitTest.Data 6 | { 7 | public class GeoHashTests 8 | { 9 | [Fact] 10 | public void Encode() 11 | { 12 | // 鸟巢 13 | Assert.Equal("wx4g8c9vn", GeoHash.Encode(116.402843, 39.999375)); 14 | // 水立方 15 | Assert.Equal("wx4g89tkz", GeoHash.Encode(116.3967, 39.99932)); 16 | // 故宫 17 | Assert.Equal("wx4g0ffev", GeoHash.Encode(116.40382, 39.918118)); 18 | } 19 | 20 | [Fact] 21 | public void Decode() 22 | { 23 | var gp1 = GeoHash.Decode("wx4g8c9vn"); 24 | Assert.True(Math.Abs(116.402843 - gp1.Longitude) < 0.0001); 25 | Assert.True(Math.Abs(39.999375 - gp1.Latitude) < 0.0001); 26 | 27 | var gp2 = GeoHash.Decode("wx4g89tkz"); 28 | Assert.True(Math.Abs(116.3967 - gp2.Longitude) < 0.0001); 29 | Assert.True(Math.Abs(39.99932 - gp2.Latitude) < 0.0001); 30 | 31 | var gp3 = GeoHash.Decode("wx4g0ffev"); 32 | Assert.True(Math.Abs(116.40382 - gp3.Longitude) < 0.0001); 33 | Assert.True(Math.Abs(39.918118 - gp3.Latitude) < 0.0001); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /XUnitTest.Core/Expressions/MathTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using NewLife; 3 | using NewLife.Expressions; 4 | using NewLife.Log; 5 | using Xunit; 6 | 7 | namespace XUnitTest.Expressions 8 | { 9 | public class MathTests 10 | { 11 | [Fact] 12 | public void Test1() 13 | { 14 | var exp = "99-(12+34*56)/78"; 15 | XTrace.WriteLine("表达式:{0}", exp); 16 | 17 | var me = new MathExpression(); 18 | var expRpn = me.ToExpression(exp); 19 | var str = expRpn.Join(","); 20 | XTrace.WriteLine("逆波兰:{0}", str); 21 | Assert.Equal("99,12,34,56,*,+,78,/,-", str); 22 | 23 | var rs = me.Complie(expRpn); 24 | XTrace.WriteLine("结 果:{0}", rs); 25 | Assert.Equal(74.43589743589743, rs); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /XUnitTest.Core/Extension/ProcessHelperTests.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using NewLife; 3 | using NewLife.Log; 4 | using Xunit; 5 | 6 | namespace XUnitTest.Extension; 7 | 8 | public class ProcessHelperTests 9 | { 10 | [Fact(Skip = "Test")] 11 | public void GetCommandLine() 12 | { 13 | foreach (var item in Process.GetProcesses()) 14 | { 15 | if (item.ProcessName == "dotnet") 16 | { 17 | var cmd = ProcessHelper.GetCommandLine(item.Id); 18 | XTrace.WriteLine("{0}: {1}", item.ProcessName, cmd); 19 | 20 | Assert.Contains("dotnet.exe", cmd); 21 | } 22 | } 23 | } 24 | 25 | [Fact(Skip = "Test")] 26 | public void GetCommandLineArgs() 27 | { 28 | foreach (var item in Process.GetProcesses()) 29 | { 30 | if (item.ProcessName == "dotnet") 31 | { 32 | var cmds = ProcessHelper.GetCommandLineArgs(item.Id); 33 | XTrace.WriteLine("{0}: {1}", item.ProcessName, cmds.Join(" ")); 34 | 35 | Assert.True(cmds.Length >= 2); 36 | Assert.EndsWith("dotnet.exe", cmds[0]); 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /XUnitTest.Core/GeoArea.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NewLife.Data 4 | { 5 | /// 地理区域 6 | public class GeoArea 7 | { 8 | #region 属性 9 | /// 编码 10 | public Int32 Code { get; set; } 11 | 12 | /// 名称 13 | public String Name { get; set; } 14 | 15 | /// 父级 16 | public Int32 ParentCode { get; set; } 17 | 18 | /// 中心 19 | public String Center { get; set; } 20 | 21 | /// 边界 22 | public String Polyline { get; set; } 23 | 24 | /// 级别 25 | public String Level { get; set; } 26 | #endregion 27 | 28 | /// 已重载。 29 | /// 30 | public override String ToString() => $"{Code} {Name}"; 31 | } 32 | } -------------------------------------------------------------------------------- /XUnitTest.Core/Http/leaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/XUnitTest.Core/Http/leaf.png -------------------------------------------------------------------------------- /XUnitTest.Core/IO/ExcelReaderTests.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using NewLife; 3 | using NewLife.IO; 4 | using Xunit; 5 | 6 | namespace XUnitTest.IO; 7 | 8 | public class ExcelReaderTests 9 | { 10 | [Fact] 11 | public void Test1() 12 | { 13 | var type = GetType(); 14 | var stream = type.Assembly.GetManifestResourceStream(type.Namespace + ".excel.xlsx"); 15 | Assert.NotNull(stream); 16 | 17 | var reader = new ExcelReader(stream, Encoding.UTF8); 18 | var rows = reader.ReadRows().ToList(); 19 | Assert.Equal(927, rows.Count); 20 | 21 | var names = "序号,名字,昵称,启用,年龄,生日,时间,余额,比率,开始时间,结束时间".Split(','); 22 | var fields = rows[0].Cast().ToArray(); 23 | Assert.Equal(names.Length, fields.Length); 24 | for (var i = 0; i < names.Length; i++) 25 | { 26 | Assert.Equal(names[i], fields[i]); 27 | } 28 | 29 | var values = "111,Stone,大石头,1,36.6,1984-07-01,2020-03-04 20:08:45,323.452,0.234,11:22:00,23:59:00".Split(','); 30 | var row1 = rows[1]; 31 | Assert.Equal(values.Length, row1.Length); 32 | for (var i = 0; i < values.Length; i++) 33 | { 34 | if (row1[i] is DateTime dt) 35 | Assert.Equal(values[i].ToDateTime(), dt); 36 | else if (row1[i] is TimeSpan ts) 37 | Assert.Equal(TimeSpan.Parse(values[i]), ts); 38 | else 39 | Assert.Equal(values[i], row1[i]); 40 | } 41 | } 42 | 43 | //[Fact] 44 | public void Test2() 45 | { 46 | var reader = new ExcelReader("test.xlsx"); 47 | var rows = reader.ReadRows().ToList(); 48 | Assert.Equal(927, rows.Count); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /XUnitTest.Core/IO/excel.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NewLifeX/X/14956ea83fd5b6946f11adbf01c08dc61e84c2c6/XUnitTest.Core/IO/excel.xlsx -------------------------------------------------------------------------------- /XUnitTest.Core/Log/LevelLogTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using NewLife.Log; 6 | using Xunit; 7 | using NewLife.Reflection; 8 | using System.Threading; 9 | 10 | namespace XUnitTest.Log 11 | { 12 | public class LevelLogTests 13 | { 14 | [Fact] 15 | public void CreateTest() 16 | { 17 | var p = "LevelLog\\"; 18 | if (Directory.Exists(p.GetFullPath())) Directory.Delete(p.GetFullPath(), true); 19 | 20 | var log = new LevelLog(p, "{1}\\{0:yyyy_MM_dd}.log"); 21 | log.Level = LogLevel.All; 22 | 23 | var logs = log.GetValue("_logs") as IDictionary; 24 | Assert.NotNull(logs); 25 | Assert.Equal(5, logs.Count); 26 | 27 | log.Debug("debug"); 28 | log.Info("info"); 29 | log.Warn("warn"); 30 | log.Error("error"); 31 | log.Fatal("fatal"); 32 | 33 | // 等待日志落盘 34 | Thread.Sleep(2000); 35 | 36 | var f = p + $"debug\\{DateTime.Today:yyyy_MM_dd}.log"; 37 | Assert.True(File.Exists(f.GetFullPath())); 38 | 39 | f = p + $"info\\{DateTime.Today:yyyy_MM_dd}.log"; 40 | Assert.True(File.Exists(f.GetFullPath())); 41 | 42 | f = p + $"warn\\{DateTime.Today:yyyy_MM_dd}.log"; 43 | Assert.True(File.Exists(f.GetFullPath())); 44 | 45 | f = p + $"error\\{DateTime.Today:yyyy_MM_dd}.log"; 46 | Assert.True(File.Exists(f.GetFullPath())); 47 | 48 | f = p + $"fatal\\{DateTime.Today:yyyy_MM_dd}.log"; 49 | Assert.True(File.Exists(f.GetFullPath())); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /XUnitTest.Core/Log/NetworkLogTests.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Log; 2 | using Xunit; 3 | 4 | namespace XUnitTest.Log; 5 | 6 | public class NetworkLogTests 7 | { 8 | [Fact] 9 | public void UdpLog() 10 | { 11 | using var netLog = new NetworkLog(); 12 | netLog.Write(LogLevel.Info, "This is {0}", Environment.MachineName); 13 | netLog.Write(LogLevel.Info, "I am {0}", Environment.UserName); 14 | } 15 | 16 | [Fact] 17 | public void TcpLog() 18 | { 19 | using var netLog = new NetworkLog("tcp://127.0.0.1:514"); 20 | netLog.Write(LogLevel.Info, "This is {0}", Environment.MachineName); 21 | netLog.Write(LogLevel.Info, "I am {0}", Environment.UserName); 22 | } 23 | 24 | [Fact] 25 | public void HttpLog() 26 | { 27 | using var netLog = new NetworkLog("http://baidu.com/log"); 28 | netLog.Write(LogLevel.Info, "This is {0}", Environment.MachineName); 29 | netLog.Write(LogLevel.Info, "I am {0}", Environment.UserName); 30 | 31 | for (var i = 0; i < 10; i++) 32 | { 33 | netLog.Write(LogLevel.Info, "Hello +" + i); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /XUnitTest.Core/Log/PerfCounterTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading; 5 | using NewLife.Log; 6 | using Xunit; 7 | using NewLife.Reflection; 8 | using System.Diagnostics; 9 | 10 | namespace XUnitTest.Log 11 | { 12 | public class PerfCounterTests 13 | { 14 | [Fact] 15 | public void Test() 16 | { 17 | var counter = new PerfCounter(); 18 | 19 | XTrace.WriteLine("IsHighResolution={0}", Stopwatch.IsHighResolution); 20 | XTrace.WriteLine("Frequency={0:n0}", Stopwatch.Frequency); 21 | var tickFrequency = typeof(CounterHelper).GetValue("tickFrequency"); 22 | XTrace.WriteLine("tickFrequency={0:n0}", tickFrequency); 23 | 24 | var ts = counter.StartCount(); 25 | var count = 10000; 26 | Thread.SpinWait(count); 27 | 28 | var usCost = counter.StopCount(ts); 29 | XTrace.WriteLine("Thread.SpinWait({0}) = {1}us", count, usCost); 30 | 31 | //Assert.True(usCost >= 1000); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /XUnitTest.Core/Net/NetSeverTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Sockets; 4 | using System.Text; 5 | using System.Threading; 6 | using NewLife; 7 | using NewLife.Log; 8 | using NewLife.Net; 9 | using Xunit; 10 | 11 | namespace XUnitTest.Net 12 | { 13 | public class NetSeverTests 14 | { 15 | [Fact] 16 | public void TcpEmptyData() 17 | { 18 | var server = new NetServer 19 | { 20 | Port = 7777, 21 | 22 | Log = XTrace.Log, 23 | SessionLog = XTrace.Log, 24 | SocketLog = XTrace.Log, 25 | LogSend = true, 26 | LogReceive = true, 27 | }; 28 | 29 | server.Received += (s, e) => 30 | { 31 | var ss = s as INetSession; 32 | ss.Send(e.Packet); 33 | }; 34 | 35 | server.Start(); 36 | 37 | { 38 | var uri = new NetUri($"tcp://127.0.0.1:{server.Port}"); 39 | var client = new TcpClient(); 40 | client.Connect(uri.EndPoint); 41 | 42 | var ns = client.GetStream(); 43 | ns.Write("Stone@NewLife.com".GetBytes()); 44 | 45 | var buf = new Byte[1024]; 46 | var rs = ns.Read(buf, 0, buf.Length); 47 | } 48 | 49 | Thread.Sleep(3_000); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /XUnitTest.Core/Net/UpgradeTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net.Http; 4 | using NewLife; 5 | using NewLife.Http; 6 | using NewLife.Log; 7 | using NewLife.Net; 8 | using Xunit; 9 | 10 | namespace XUnitTest.Net 11 | { 12 | public class UpgradeTests 13 | { 14 | [Fact] 15 | public void CopyAndReplace() 16 | { 17 | //Directory.Delete("./Update", true); 18 | 19 | var url = "http://x.newlifex.com/star/staragent50.zip"; 20 | var fileName = Path.GetFileName(url); 21 | //fileName = "Update".CombinePath(fileName).EnsureDirectory(true); 22 | 23 | var ug = new Upgrade { Log = XTrace.Log }; 24 | ug.Download(url, fileName); 25 | 26 | // 解压 27 | var source = ug.Extract(ug.SourceFile); 28 | 29 | // 覆盖 30 | var dest = "./updateTest"; 31 | ug.CopyAndReplace(source, dest); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /XUnitTest.Core/PropertyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Xunit; 5 | 6 | //[assembly: TestCaseOrderer("Xunit.Extensions.Ordering.TestCaseOrderer", "Xunit.Extensions.Ordering")] -------------------------------------------------------------------------------- /XUnitTest.Core/Reflection/AssemblyXTests.cs: -------------------------------------------------------------------------------- 1 | using NewLife; 2 | using NewLife.Reflection; 3 | using Xunit; 4 | 5 | namespace XUnitTest.Reflection; 6 | 7 | public class AssemblyXTests 8 | { 9 | [Fact] 10 | public void GetCompileTime() 11 | { 12 | { 13 | var ver = "2.0.8153.37437"; 14 | var time = AssemblyX.GetCompileTime(ver); 15 | Assert.Equal("2022-04-28 20:47:54".ToDateTime(), time); 16 | } 17 | { 18 | var ver = "9.0.2022.427"; 19 | var time = AssemblyX.GetCompileTime(ver); 20 | Assert.Equal("2022-04-27 00:00:00".ToDateTime(), time); 21 | } 22 | { 23 | var ver = "9.0.2022.0427-beta0344"; 24 | var time = AssemblyX.GetCompileTime(ver); 25 | Assert.Equal("2022-04-27 03:44:00".ToDateTime(), time.ToUniversalTime()); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /XUnitTest.Core/Security/Crc16Tests.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Security; 2 | using Xunit; 3 | 4 | namespace XUnitTest.Security; 5 | 6 | public class Crc16Tests 7 | { 8 | [Fact] 9 | public void TestComputeWithByteArray() 10 | { 11 | var data = "123456789"u8.ToArray(); 12 | var crc = Crc16.Compute(data); 13 | Assert.Equal(0x31C3, crc); 14 | } 15 | 16 | [Fact] 17 | public void TestComputeWithStream() 18 | { 19 | var data = "123456789"u8.ToArray(); 20 | using var stream = new MemoryStream(data); 21 | var crc = Crc16.Compute(stream, -1); 22 | Assert.Equal(0x31C3, crc); 23 | } 24 | 25 | [Fact] 26 | public void TestComputeWithReadOnlySpan() 27 | { 28 | var data = "123456789"u8.ToArray(); 29 | var crc = Crc16.Compute(new ReadOnlySpan(data)); 30 | Assert.Equal(0x31C3, crc); 31 | } 32 | 33 | [Fact] 34 | public void TestComputeModbusWithByteArray() 35 | { 36 | var data = "123456789"u8.ToArray(); 37 | var crc = Crc16.ComputeModbus(data, 0); 38 | Assert.Equal(0x4B37, crc); 39 | } 40 | 41 | [Fact] 42 | public void TestComputeModbusWithStream() 43 | { 44 | var data = "123456789"u8.ToArray(); 45 | using var stream = new MemoryStream(data); 46 | var crc = Crc16.ComputeModbus(stream); 47 | Assert.Equal(0x4B37, crc); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /XUnitTest.Core/Security/KeyBlobMagicNumber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace XUnitTest.Security 7 | { 8 | enum KeyBlobMagicNumber 9 | { 10 | ECDH_PUBLIC_P256 = 0x314B4345, 11 | ECDH_PRIVATE_P256 = 0x324B4345, 12 | ECDH_PUBLIC_P384 = 0x334B4345, 13 | ECDH_PRIVATE_P384 = 0x344B4345, 14 | ECDH_PUBLIC_P521 = 0x354B4345, 15 | ECDH_PRIVATE_P521 = 0x364B4345, 16 | ECDH_PUBLIC_GENERIC = 0x504B4345, 17 | ECDH_PRIVATE_GENERIC = 0x564B4345, 18 | ECDSA_PUBLIC_P256 = 0x31534345, 19 | ECDSA_PRIVATE_P256 = 0x32534345, 20 | ECDSA_PUBLIC_P384 = 0x33534345, 21 | ECDSA_PRIVATE_P384 = 0x34534345, 22 | ECDSA_PUBLIC_P521 = 0x35534345, 23 | ECDSA_PRIVATE_P521 = 0x36534345, 24 | ECDSA_PUBLIC_GENERIC = 0x50444345, 25 | ECDSA_PRIVATE_GENERIC = 0x56444345, 26 | RSAPUBLIC = 0x31415352, 27 | RSAPRIVATE = 0x32415352, 28 | RSAFULLPRIVATE = 0x33415352, 29 | KEY_DATA_BLOB = 0x4D42444B 30 | } 31 | } -------------------------------------------------------------------------------- /XUnitTest.Core/Security/RandTests.cs: -------------------------------------------------------------------------------- 1 | using NewLife.Data; 2 | using NewLife.Security; 3 | using Xunit; 4 | 5 | namespace XUnitTest.Security 6 | { 7 | public class RandTests 8 | { 9 | [Fact] 10 | public void Fill() 11 | { 12 | var area = new GeoArea(); 13 | Rand.Fill(area); 14 | 15 | Assert.True(area.Code > 0); 16 | Assert.NotEmpty(area.Name); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /XUnitTest.Core/Serialization/FDLibBaseCfg.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Xml.Serialization; 7 | 8 | namespace XUnitTest.Serialization 9 | { 10 | public class FDLibBaseCfg 11 | { 12 | /// 13 | /// 14 | /// 15 | public string id { get; set; } 16 | 17 | /// 18 | /// 19 | /// 20 | public string FDID { get; set; } 21 | 22 | /// 23 | /// 24 | /// 25 | public string name { get; set; } 26 | 27 | /// 28 | /// 29 | /// 30 | public string faceLibType { get; set; } 31 | 32 | } 33 | 34 | [XmlRootAttribute("FDLibBaseCfgList", Namespace = "http://www.isapi.org/ver20/XMLSchema")] 35 | public class FDLibBaseCfgList 36 | { 37 | 38 | public string xmlns { get; set; } 39 | /// 40 | /// 41 | /// 42 | [XmlAttribute] 43 | public string version { get; set; } 44 | 45 | /// 46 | /// FDLibBaseCfg 47 | /// 48 | [XmlElement("FDLibBaseCfg")] 49 | public IList FDLibBaseCfgs { get; set; } 50 | 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /XUnitTest.Core/Serialization/StarAgent.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 6 | 7F0F011A 7 | 8 | iyvV8YhOA5DfQuta 9 | 10 | udp://127.0.0.1:5500 11 | 12 | Release 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /XUnitTest.Core/Web/TokenProviderTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using NewLife; 5 | using NewLife.Security; 6 | using NewLife.Web; 7 | using Xunit; 8 | 9 | namespace XUnitTest.Web; 10 | 11 | public class TokenProviderTests 12 | { 13 | [Fact] 14 | public void Test() 15 | { 16 | var prv = new TokenProvider(); 17 | 18 | // 加载或生成密钥 19 | var rs = prv.ReadKey("keys/test.prvkey", true); 20 | Assert.True(rs); 21 | Assert.True(File.Exists("keys/test.prvkey".GetFullPath())); 22 | Assert.True(File.Exists("keys/test.pubkey".GetFullPath())); 23 | Assert.NotEmpty(prv.Key); 24 | 25 | // 生成令牌 26 | var user = Rand.NextString(8); 27 | var time = DateTime.Now.AddHours(2); 28 | var token = prv.Encode(user, time); 29 | 30 | Assert.NotEmpty(token); 31 | var data = token.Substring(null, ".").ToBase64().ToStr(); 32 | Assert.Equal($"{user},{time.ToUniversalTime().ToInt()}", data); 33 | 34 | // 解码令牌 35 | var prv2 = new TokenProvider(); 36 | prv2.ReadKey("keys/test.pubkey", false); 37 | var rs2 = prv2.TryDecode(token, out var user2, out var time2); 38 | 39 | Assert.True(rs2); 40 | Assert.Equal(user, user2); 41 | Assert.Equal(time.Trim(), time2.Trim()); 42 | 43 | // 破坏数据 44 | token = $"Stone,{time.ToUniversalTime().ToInt()}".GetBytes().ToUrlBase64() + "." + token.Substring("."); 45 | var rs3 = prv2.TryDecode(token, out var user3, out var time3); 46 | 47 | Assert.False(rs3); 48 | Assert.NotEqual(user, user3); 49 | Assert.Equal(time.Trim(), time3.Trim()); 50 | } 51 | } -------------------------------------------------------------------------------- /XUnitTest.Core/Web/WebClientTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using NewLife; 5 | using NewLife.Web; 6 | using Xunit; 7 | 8 | namespace XUnitTest.Web; 9 | 10 | public class WebClientTests 11 | { 12 | [Fact] 13 | public void GetLinks() 14 | { 15 | var client = new WebClientX(); 16 | var links = client.GetLinks("http://x.newlifex.com"); 17 | Assert.NotEmpty(links); 18 | 19 | var names = "System.Data.SQLite.win-x64,System.Data.SQLite.win,System.Data.SQLite_net80,System.Data.SQLite_netstandard21,System.Data.SQLite_netstandard20,System.Data.SQLite".Split(",", ";"); 20 | 21 | links = links.Where(e => e.Name.EqualIgnoreCase(names) || e.FullName.EqualIgnoreCase(names)).ToArray(); 22 | var link = links.OrderByDescending(e => e.Version).ThenByDescending(e => e.Time).FirstOrDefault(); 23 | 24 | Assert.NotNull(link); 25 | Assert.Equal("System.Data.SQLite.win-x64", link.Name); 26 | Assert.True(link.Time >= "2024-05-14".ToDateTime()); 27 | Assert.Null(link.Version); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /XUnitTest.Core/Yun/BaiduMapTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using NewLife.Http; 7 | using NewLife.Yun; 8 | using Xunit; 9 | using NewLife; 10 | using System.Net.Http; 11 | 12 | namespace XUnitTest.Yun 13 | { 14 | public class BaiduMapTests 15 | { 16 | [Fact] 17 | public async void IpLocation() 18 | { 19 | var html = new HttpClient().GetString("http://myip.ipip.net"); 20 | var ip = html?.Substring("IP:", " "); 21 | Assert.NotEmpty(ip); 22 | 23 | var map = new BaiduMap(); 24 | var rs = await map.IpLocationAsync(ip); 25 | 26 | Assert.NotNull(rs); 27 | 28 | var addrs = (rs["full_address"] + "").Split('|'); 29 | Assert.Equal(7, addrs.Length); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /XUnitTest.Core/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Url": "https://newlifex.com/", 3 | "Title": "本地标题", 4 | "ConnectionStrings": { 5 | "MySQL.AppSettings": { 6 | "connectionString": /*中间注释*/ "Server=.;Port=3306;Database=mysql;Uid=MySQL.default;Pwd=;", 7 | "providerName": "MySql.Data.MySqlClient" 8 | // 不支持放在最后的注释,链接中的双斜杠被当成注释 9 | // 独立一行注释 10 | }, 11 | "sqlserver": { 12 | "connectionString": "Server=127.0.0.1;Database=Membership;Uid=root;Pwd=root;", 13 | "providerName": "SqlServer" 14 | }, 15 | "MySQL.AppSettings.default": { 16 | /*"connectionString": "Server=.;Port=3306;Database=mysql;Uid=MySQL.default;Pwd=;",*/ 17 | /*"providerName": "MySql.Data.MySqlClient"*/ 18 | }, 19 | "TDengine": { 20 | "connectionString": "Server=gz01.newlifex.com;Port=6030;Database=db;user=root;password=taosdata", 21 | "providerName": "TDengine" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.0", 4 | "rollForward": "latestMajor", 5 | "allowPrerelease": true 6 | } 7 | } 8 | --------------------------------------------------------------------------------