我当前正在尝试将android应用程序连接到本地ASP.NET后端。
这样做时,我不断收到错误消息
Retrofit Unexpected end of stream Connection
我真的不知道我错了。我查看了其他解决方案,但似乎没有一个对我有帮助。
我读过一些有关内容长度的问题。在Startup.cs的configure方法中,我注意到以下代码。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, DataInitializer dataInitializer)
{
app.Use(async (ctx, next) =>
{
await next();
if (ctx.Response.StatusCode == 204)
{
ctx.Response.ContentLength = 0;
}
});
但是我不知道这是否是造成我问题的原因。
下面,我添加了可能是问题一部分的其余代码。
.Net的Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
//AddScopeds for each repository//
//...//
services.AddCors(o => o.AddPolicy("AllowAllOrigins", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}));
services.AddIdentity<IdentityUser, IdentityRole>(cfg => cfg.User.RequireUniqueEmail = true).AddEntityFrameworkStores<ApplicationDbContext>();
services.AddOpenApiDocument(
c =>
{
c.DocumentName = "apidocs";
c.Title = "Test API";
c.Version = "v1";
c.Description = "The Test API documentation description.";
c.DocumentProcessors.Add(new SecurityDefinitionAppender("JWT Token", new SwaggerSecurityScheme
{
Type = SwaggerSecuritySchemeType.ApiKey,
Name = "Authorization",
In = SwaggerSecurityApiKeyLocation.Header,
Description = "Copy 'Bearer' + valid JWT token into field"
}));
c.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT Token"));
}
);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme =
JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(Configuration["Tokens:Key"])),
ValidateIssuer = false,
ValidateAudience = false,
RequireExpirationTime = true //Ensure token hasn't expired
};
});
services.Configure<IdentityOptions>(options =>
{
// Password settings.
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 8;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
options.User.RequireUniqueEmail = true;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, KlimaatMobielDataInitializer dataInitializer)
{
app.Use(async (ctx, next) =>
{
await next();
if (ctx.Response.StatusCode == 204)
{
ctx.Response.ContentLength = 0;
}
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseCors("AllowAllOrigins"); //
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", @"Resources")),
RequestPath = new PathString("/Resources")
});
app.UseHttpsRedirection();
app.UseMvc();
app.UseSwaggerUi3();
app.UseSwagger();
app.UseAuthentication();
}
}
改造界面
private const val BASE_URL = "http://10.0.2.2:5001/api/"
private val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.baseUrl(BASE_URL)
.build()
interface TestApiService {
@GET("material")
fun getMaterials():
Call<List<Material>>
}
object TestApi {
val retrofitService: KlimaatApiService by lazy {
retrofit.create(KlimaatApiService::class.java)
}
}
使用界面
public fun getMaterialen() {
Timber.plant(Timber.DebugTree())
KlimaatApi.retrofitService.getMaterialen().enqueue(object : Callback<List<Material>> {
override fun onFailure(call: Call<List<Material>>, t: Throwable) {
_response.value = "Failure: " + t.message
Timber.e(t.message)
}
override fun onResponse(
call: Call<List<Material>>,
response: Response<List<Material>>
) {
if(!response.isSuccessful){
Timber.e("Code: ${response.code()}")
}
var materials = response.body()
for(mat in materials!!){
Timber.e(mat.name)
}
}
})
}