@ -0,0 +1,3 @@ | |||
* | |||
!obj/Docker/publish/* | |||
!obj/Docker/empty/ |
@ -0,0 +1,19 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
using Microsoft.AspNetCore.Mvc; | |||
// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 | |||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Controllers | |||
{ | |||
public class HomeController : Controller | |||
{ | |||
// GET: /<controller>/ | |||
public IActionResult Index() | |||
{ | |||
return new RedirectResult("~/swagger"); | |||
} | |||
} | |||
} |
@ -0,0 +1,44 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
using Microsoft.AspNetCore.Mvc; | |||
namespace Locations.API.Controllers | |||
{ | |||
[Route("api/[controller]")] | |||
public class ValuesController : Controller | |||
{ | |||
// GET api/values | |||
[HttpGet] | |||
public IEnumerable<string> Get() | |||
{ | |||
return new string[] { "value1", "value2" }; | |||
} | |||
// GET api/values/5 | |||
[HttpGet("{id}")] | |||
public string Get(int id) | |||
{ | |||
return "value"; | |||
} | |||
// POST api/values | |||
[HttpPost] | |||
public void Post([FromBody]string value) | |||
{ | |||
} | |||
// PUT api/values/5 | |||
[HttpPut("{id}")] | |||
public void Put(int id, [FromBody]string value) | |||
{ | |||
} | |||
// DELETE api/values/5 | |||
[HttpDelete("{id}")] | |||
public void Delete(int id) | |||
{ | |||
} | |||
} | |||
} |
@ -0,0 +1,6 @@ | |||
FROM microsoft/aspnetcore:1.1 | |||
ARG source | |||
WORKDIR /app | |||
EXPOSE 80 | |||
COPY ${source:-obj/Docker/publish} . | |||
ENTRYPOINT ["dotnet", "Locations.API.dll"] |
@ -0,0 +1,55 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure | |||
{ | |||
using Microsoft.EntityFrameworkCore; | |||
using Microsoft.EntityFrameworkCore.Metadata.Builders; | |||
using Microsoft.eShopOnContainers.Services.Locations.API.Model; | |||
public class LocationsContext : DbContext | |||
{ | |||
public LocationsContext(DbContextOptions options) : base(options) | |||
{ | |||
} | |||
public DbSet<Locations> Locations { get; set; } | |||
protected override void OnModelCreating(ModelBuilder builder) | |||
{ | |||
builder.Entity<Locations>(ConfigureLocations); | |||
builder.Entity<FrontierPoints>(ConfigureFrontierPoints); | |||
} | |||
void ConfigureLocations(EntityTypeBuilder<Locations> builder) | |||
{ | |||
builder.ToTable("Locations"); | |||
builder.HasKey(cl => cl.Id); | |||
builder.Property(cl => cl.Id) | |||
.ForSqlServerUseSequenceHiLo("locations_hilo") | |||
.IsRequired(); | |||
builder.Property(cb => cb.Code) | |||
.IsRequired() | |||
.HasColumnName("LocationCode") | |||
.HasMaxLength(15); | |||
builder.HasMany(f => f.Polygon) | |||
.WithOne(l => l.Location) | |||
.IsRequired(); | |||
builder.Property(cb => cb.Description) | |||
.HasMaxLength(100); | |||
} | |||
void ConfigureFrontierPoints(EntityTypeBuilder<FrontierPoints> builder) | |||
{ | |||
builder.ToTable("FrontierPoints"); | |||
builder.HasKey(fp => fp.Id); | |||
builder.Property(fp => fp.Id) | |||
.ForSqlServerUseSequenceHiLo("frontier_hilo") | |||
.IsRequired(); | |||
} | |||
} | |||
} |
@ -0,0 +1,131 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure | |||
{ | |||
using Microsoft.AspNetCore.Builder; | |||
using Microsoft.EntityFrameworkCore; | |||
using Microsoft.Extensions.Logging; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
using Microsoft.eShopOnContainers.Services.Locations.API.Model; | |||
using System.Text; | |||
public class LocationsContextSeed | |||
{ | |||
public static async Task SeedAsync(IApplicationBuilder applicationBuilder, ILoggerFactory loggerFactory) | |||
{ | |||
var context = (LocationsContext)applicationBuilder | |||
.ApplicationServices.GetService(typeof(LocationsContext)); | |||
context.Database.Migrate(); | |||
if (!context.Locations.Any()) | |||
{ | |||
context.Locations.AddRange( | |||
GetPreconfiguredLocations()); | |||
await context.SaveChangesAsync(); | |||
} | |||
} | |||
static Locations GetPreconfiguredLocations() | |||
{ | |||
var ww = new Locations() { Code = "WW", Description = "WorldWide", Latitude = -1, Longitude = -1 }; | |||
ww.ChildLocations.Add(GetUSLocations()); | |||
return ww; | |||
} | |||
static Locations GetUSLocations() | |||
{ | |||
var us = new Locations() { Code = "US", Description = "United States", Latitude = 41.650455, Longitude = -101.357386, Polygon = GetUSPoligon() }; | |||
us.ChildLocations.Add(GetWashingtonLocations()); | |||
return us; | |||
} | |||
static Locations GetWashingtonLocations() | |||
{ | |||
var wht = new Locations() { Code = "WHT", Description = "Washington", Latitude = 47.223652, Longitude = -119.542781, Polygon = GetWashingtonPoligon() }; | |||
wht.ChildLocations.Add(GetSeattleLocations()); | |||
wht.ChildLocations.Add(GetRedmondLocations()); | |||
return wht; | |||
} | |||
static Locations GetSeattleLocations() | |||
{ | |||
var bcn = new Locations() { Code = "SEAT", Description = "Seattle", Latitude = 47.603111, Longitude = -122.330747, Polygon = GetSeattlePoligon() }; | |||
bcn.ChildLocations.Add(new Locations() { Code = "SEAT-PioneerSqr", Description = "Seattle Pioneer Square Shop" , Latitude = 47.602053, Longitude= -122.333884, Polygon = GetSeattlePioneerSqrPoligon() }); | |||
return bcn; | |||
} | |||
static Locations GetRedmondLocations() | |||
{ | |||
var bcn = new Locations() { Code = "REDM", Description = "Redmond", Latitude = 47.674961, Longitude = -122.122887, Polygon = GetRedmondPoligon() }; | |||
bcn.ChildLocations.Add(new Locations() { Code = "REDM-DWNTWP", Description = "Redmond Downtown Central Park Shop", Latitude = 47.674433, Longitude = -122.125006, Polygon = GetRedmondDowntownParkPoligon() }); | |||
return bcn; | |||
} | |||
static List<FrontierPoints> GetUSPoligon() | |||
{ | |||
var poligon = new List<FrontierPoints>(); | |||
poligon.Add(new FrontierPoints() { Latitude = 48.7985, Longitude = -62.88205 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 48.76513, Longitude = -129.31329 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 30.12256, Longitude = -120.9496 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 30.87114, Longitude = -111.39442 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 24.24979, Longitude = -78.11975 }); | |||
return poligon; | |||
} | |||
static List<FrontierPoints> GetWashingtonPoligon() | |||
{ | |||
var poligon = new List<FrontierPoints>(); | |||
poligon.Add(new FrontierPoints() { Latitude = 48.8943, Longitude = -124.68633 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 45.66613, Longitude = -124.32962 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 45.93384, Longitude = -116.73824 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 49.04282, Longitude = -116.96912 }); | |||
return poligon; | |||
} | |||
static List<FrontierPoints> GetSeattlePoligon() | |||
{ | |||
var poligon = new List<FrontierPoints>(); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.82929, Longitude = -122.36238 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.6337, Longitude = -122.42091 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.45224, Longitude = -122.37371 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.50259, Longitude = -122.20788 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.73644, Longitude = -122.26934 }); | |||
return poligon; | |||
} | |||
static List<FrontierPoints> GetRedmondPoligon() | |||
{ | |||
var poligon = new List<FrontierPoints>(); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.73148, Longitude = -122.15432 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.72559, Longitude = -122.17673 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.67851, Longitude = -122.16904 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.65036, Longitude = -122.16136 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.62746, Longitude = -122.15604 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.63463, Longitude = -122.01562 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.74244, Longitude = -122.04961 }); | |||
return poligon; | |||
} | |||
static List<FrontierPoints> GetSeattlePioneerSqrPoligon() | |||
{ | |||
var poligon = new List<FrontierPoints>(); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.60338, Longitude = -122.3327 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.60192, Longitude = -122.33665 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.60096, Longitude = -122.33456 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.60136, Longitude = -122.33186 }); | |||
return poligon; | |||
} | |||
static List<FrontierPoints> GetRedmondDowntownParkPoligon() | |||
{ | |||
var poligon = new List<FrontierPoints>(); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.67595, Longitude = -122.12467 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.67449, Longitude = -122.12862 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.67353, Longitude = -122.12653 }); | |||
poligon.Add(new FrontierPoints() { Latitude = 47.67368, Longitude = -122.12197 }); | |||
return poligon; | |||
} | |||
} | |||
} |
@ -0,0 +1,87 @@ | |||
using System; | |||
using Microsoft.EntityFrameworkCore; | |||
using Microsoft.EntityFrameworkCore.Infrastructure; | |||
using Microsoft.EntityFrameworkCore.Metadata; | |||
using Microsoft.EntityFrameworkCore.Migrations; | |||
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure; | |||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Migrations | |||
{ | |||
[DbContext(typeof(LocationsContext))] | |||
[Migration("20170529174524_Initial")] | |||
partial class Initial | |||
{ | |||
protected override void BuildTargetModel(ModelBuilder modelBuilder) | |||
{ | |||
modelBuilder | |||
.HasAnnotation("ProductVersion", "1.1.2") | |||
.HasAnnotation("SqlServer:Sequence:.frontier_hilo", "'frontier_hilo', '', '1', '10', '', '', 'Int64', 'False'") | |||
.HasAnnotation("SqlServer:Sequence:.locations_hilo", "'locations_hilo', '', '1', '10', '', '', 'Int64', 'False'") | |||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); | |||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.FrontierPoints", b => | |||
{ | |||
b.Property<int>("Id") | |||
.ValueGeneratedOnAdd() | |||
.HasAnnotation("SqlServer:HiLoSequenceName", "frontier_hilo") | |||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo); | |||
b.Property<double>("Latitude"); | |||
b.Property<int?>("LocationId") | |||
.IsRequired(); | |||
b.Property<double>("Longitude"); | |||
b.HasKey("Id"); | |||
b.HasIndex("LocationId"); | |||
b.ToTable("FrontierPoints"); | |||
}); | |||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations", b => | |||
{ | |||
b.Property<int>("Id") | |||
.ValueGeneratedOnAdd() | |||
.HasAnnotation("SqlServer:HiLoSequenceName", "locations_hilo") | |||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo); | |||
b.Property<string>("Code") | |||
.IsRequired() | |||
.HasColumnName("LocationCode") | |||
.HasMaxLength(15); | |||
b.Property<string>("Description") | |||
.HasMaxLength(100); | |||
b.Property<double>("Latitude"); | |||
b.Property<double>("Longitude"); | |||
b.Property<int?>("ParentId"); | |||
b.HasKey("Id"); | |||
b.HasIndex("ParentId"); | |||
b.ToTable("Locations"); | |||
}); | |||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.FrontierPoints", b => | |||
{ | |||
b.HasOne("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations", "Location") | |||
.WithMany("FrontierPoints") | |||
.HasForeignKey("LocationId") | |||
.OnDelete(DeleteBehavior.Cascade); | |||
}); | |||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations", b => | |||
{ | |||
b.HasOne("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations") | |||
.WithMany("ChildLocations") | |||
.HasForeignKey("ParentId"); | |||
}); | |||
} | |||
} | |||
} |
@ -0,0 +1,129 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Microsoft.EntityFrameworkCore.Migrations; | |||
using System.Text; | |||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Migrations | |||
{ | |||
public partial class Initial : Migration | |||
{ | |||
protected override void Up(MigrationBuilder migrationBuilder) | |||
{ | |||
migrationBuilder.CreateSequence( | |||
name: "frontier_hilo", | |||
incrementBy: 10); | |||
migrationBuilder.CreateSequence( | |||
name: "locations_hilo", | |||
incrementBy: 10); | |||
migrationBuilder.CreateTable( | |||
name: "Locations", | |||
columns: table => new | |||
{ | |||
Id = table.Column<int>(nullable: false), | |||
LocationCode = table.Column<string>(maxLength: 15, nullable: false), | |||
Description = table.Column<string>(maxLength: 100, nullable: true), | |||
Latitude = table.Column<double>(nullable: false), | |||
Longitude = table.Column<double>(nullable: false), | |||
ParentId = table.Column<int>(nullable: true) | |||
}, | |||
constraints: table => | |||
{ | |||
table.PrimaryKey("PK_Locations", x => x.Id); | |||
table.ForeignKey( | |||
name: "FK_Locations_Locations_ParentId", | |||
column: x => x.ParentId, | |||
principalTable: "Locations", | |||
principalColumn: "Id", | |||
onDelete: ReferentialAction.Restrict); | |||
}); | |||
migrationBuilder.CreateTable( | |||
name: "FrontierPoints", | |||
columns: table => new | |||
{ | |||
Id = table.Column<int>(nullable: false), | |||
Latitude = table.Column<double>(nullable: false), | |||
LocationId = table.Column<int>(nullable: false), | |||
Longitude = table.Column<double>(nullable: false) | |||
}, | |||
constraints: table => | |||
{ | |||
table.PrimaryKey("PK_FrontierPoints", x => x.Id); | |||
table.ForeignKey( | |||
name: "FK_FrontierPoints_Locations_LocationId", | |||
column: x => x.LocationId, | |||
principalTable: "Locations", | |||
principalColumn: "Id", | |||
onDelete: ReferentialAction.Cascade); | |||
}); | |||
migrationBuilder.CreateIndex( | |||
name: "IX_FrontierPoints_LocationId", | |||
table: "FrontierPoints", | |||
column: "LocationId"); | |||
migrationBuilder.CreateIndex( | |||
name: "IX_Locations_ParentId", | |||
table: "Locations", | |||
column: "ParentId"); | |||
migrationBuilder.Sql(CreateGetDistanceFunction()); | |||
migrationBuilder.Sql(CreateLocationsNearSP()); | |||
} | |||
protected override void Down(MigrationBuilder migrationBuilder) | |||
{ | |||
migrationBuilder.DropTable( | |||
name: "FrontierPoints"); | |||
migrationBuilder.DropTable( | |||
name: "Locations"); | |||
migrationBuilder.DropSequence( | |||
name: "frontier_hilo"); | |||
migrationBuilder.DropSequence( | |||
name: "locations_hilo"); | |||
migrationBuilder.Sql(@"DROP PROCEDURE IF EXISTS pLocationsNear"); | |||
migrationBuilder.Sql(@"DROP FUNCTION IF EXISTS dbo.GetDistanceFromLocation"); | |||
} | |||
private string CreateLocationsNearSP() | |||
{ | |||
var sb = new StringBuilder(); | |||
sb.AppendLine(@"CREATE PROCEDURE [dbo].[pLocationsNear]"); | |||
sb.AppendLine(@"@latitude float,"); | |||
sb.AppendLine(@"@longitude float,"); | |||
sb.AppendLine(@"@size int = 500"); | |||
sb.AppendLine(@"AS"); | |||
sb.AppendLine(@"BEGIN"); | |||
sb.AppendLine(@"SELECT TOP( @size) location.*"); | |||
sb.AppendLine(@"FROM [dbo].[Locations] AS location"); | |||
sb.AppendLine(@"ORDER BY dbo.[GetDistanceFromLocation](location.Latitude, location.Longitude, @latitude, @longitude)"); | |||
sb.AppendLine(@"END"); | |||
return sb.ToString(); | |||
} | |||
private string CreateGetDistanceFunction() | |||
{ | |||
var sb = new StringBuilder(); | |||
sb.AppendLine(@"CREATE FUNCTION [dbo].[GetDistanceFromLocation]("); | |||
sb.AppendLine(@"@CurrentLatitude float,"); | |||
sb.AppendLine(@"@CurrentLongitude float,"); | |||
sb.AppendLine(@"@latitude float,"); | |||
sb.AppendLine(@"@longitude float)"); | |||
sb.AppendLine(@"RETURNS int"); | |||
sb.AppendLine(@"AS"); | |||
sb.AppendLine(@"BEGIN"); | |||
sb.AppendLine(@"DECLARE @geo1 geography = geography::Point(@CurrentLatitude, @CurrentLongitude, 4268),@geo2 geography = geography::Point(@latitude, @longitude, 4268)"); | |||
sb.AppendLine(@"DECLARE @distance int"); | |||
sb.AppendLine(@"SELECT @distance = @geo1.STDistance(@geo2)"); | |||
sb.AppendLine(@"RETURN @distance"); | |||
sb.AppendLine(@"END"); | |||
return sb.ToString(); | |||
} | |||
} | |||
} |
@ -0,0 +1,86 @@ | |||
using System; | |||
using Microsoft.EntityFrameworkCore; | |||
using Microsoft.EntityFrameworkCore.Infrastructure; | |||
using Microsoft.EntityFrameworkCore.Metadata; | |||
using Microsoft.EntityFrameworkCore.Migrations; | |||
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure; | |||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Migrations | |||
{ | |||
[DbContext(typeof(LocationsContext))] | |||
partial class LocationsContextModelSnapshot : ModelSnapshot | |||
{ | |||
protected override void BuildModel(ModelBuilder modelBuilder) | |||
{ | |||
modelBuilder | |||
.HasAnnotation("ProductVersion", "1.1.2") | |||
.HasAnnotation("SqlServer:Sequence:.frontier_hilo", "'frontier_hilo', '', '1', '10', '', '', 'Int64', 'False'") | |||
.HasAnnotation("SqlServer:Sequence:.locations_hilo", "'locations_hilo', '', '1', '10', '', '', 'Int64', 'False'") | |||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); | |||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.FrontierPoints", b => | |||
{ | |||
b.Property<int>("Id") | |||
.ValueGeneratedOnAdd() | |||
.HasAnnotation("SqlServer:HiLoSequenceName", "frontier_hilo") | |||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo); | |||
b.Property<double>("Latitude"); | |||
b.Property<int?>("LocationId") | |||
.IsRequired(); | |||
b.Property<double>("Longitude"); | |||
b.HasKey("Id"); | |||
b.HasIndex("LocationId"); | |||
b.ToTable("FrontierPoints"); | |||
}); | |||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations", b => | |||
{ | |||
b.Property<int>("Id") | |||
.ValueGeneratedOnAdd() | |||
.HasAnnotation("SqlServer:HiLoSequenceName", "locations_hilo") | |||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo); | |||
b.Property<string>("Code") | |||
.IsRequired() | |||
.HasColumnName("LocationCode") | |||
.HasMaxLength(15); | |||
b.Property<string>("Description") | |||
.HasMaxLength(100); | |||
b.Property<double>("Latitude"); | |||
b.Property<double>("Longitude"); | |||
b.Property<int?>("ParentId"); | |||
b.HasKey("Id"); | |||
b.HasIndex("ParentId"); | |||
b.ToTable("Locations"); | |||
}); | |||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.FrontierPoints", b => | |||
{ | |||
b.HasOne("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations", "Location") | |||
.WithMany("FrontierPoints") | |||
.HasForeignKey("LocationId") | |||
.OnDelete(DeleteBehavior.Cascade); | |||
}); | |||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations", b => | |||
{ | |||
b.HasOne("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations") | |||
.WithMany("ChildLocations") | |||
.HasForeignKey("ParentId"); | |||
}); | |||
} | |||
} | |||
} |
@ -0,0 +1,39 @@ | |||
<Project Sdk="Microsoft.NET.Sdk.Web"> | |||
<PropertyGroup> | |||
<TargetFramework>netcoreapp1.1</TargetFramework> | |||
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath> | |||
<RootNamespace>Microsoft.eShopOnContainers.Services.Locations.API</RootNamespace> | |||
<UserSecretsId>aspnet-Locations.API-20161122013619</UserSecretsId> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Folder Include="Infrastructure\Migrations\" /> | |||
<Folder Include="Infrastructure\Migrations\" /> | |||
<Folder Include="wwwroot\" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="1.2.0" /> | |||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" /> | |||
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" /> | |||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" /> | |||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.2" /> | |||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.2" /> | |||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="1.1.2" /> | |||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.2" /> | |||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.2" /> | |||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.1" /> | |||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.2" /> | |||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.2" /> | |||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" /> | |||
<PackageReference Include="Microsoft.Extensions.Options" Version="1.1.2" /> | |||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" /> | |||
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.1" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" /> | |||
</ItemGroup> | |||
</Project> |
@ -0,0 +1,11 @@ | |||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Model | |||
{ | |||
public class FrontierPoints | |||
{ | |||
public int Id { get; set; } | |||
public double Latitude { get; set; } | |||
public double Longitude { get; set; } | |||
public Locations Location { get; set; } | |||
} | |||
} |
@ -0,0 +1,62 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.ComponentModel.DataAnnotations.Schema; | |||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Model | |||
{ | |||
public class Locations | |||
{ | |||
public int Id { get; set; } | |||
public string Code { get; set; } | |||
public int? ParentId { get; set; } | |||
public string Description { get; set; } | |||
public double Latitude { get; set; } | |||
public double Longitude { get; set; } | |||
public bool IsPointInPolygon(double lat, double lon) => CheckIsPointInPolygon(lat, lon); | |||
public Locations() | |||
{ | |||
ChildLocations = new List<Locations>(); | |||
} | |||
public virtual List<FrontierPoints> Polygon { get; set; } | |||
[ForeignKey("ParentId")] | |||
public virtual List<Locations> ChildLocations { get; set; } | |||
private bool CheckIsPointInPolygon(double lat, double lon) | |||
{ | |||
double minX = Polygon[0].Latitude; | |||
double maxX = Polygon[0].Latitude; | |||
double minY = Polygon[0].Longitude; | |||
double maxY = Polygon[0].Longitude; | |||
for (int i = 1; i < Polygon.Count; i++) | |||
{ | |||
FrontierPoints q = Polygon[i]; | |||
minX = Math.Min(q.Latitude, minX); | |||
maxX = Math.Max(q.Latitude, maxX); | |||
minY = Math.Min(q.Longitude, minY); | |||
maxY = Math.Max(q.Longitude, maxY); | |||
} | |||
if (lat < minX || lat > maxX || lon < minY || lon > maxY) | |||
{ | |||
return false; | |||
} | |||
bool inside = false; | |||
for (int i = 0, j = Polygon.Count - 1; i < Polygon.Count; j = i++) | |||
{ | |||
if ((Polygon[i].Longitude > lon) != (Polygon[j].Latitude > lat) && | |||
lat < (Polygon[j].Longitude - Polygon[i].Latitude) * (lon - Polygon[i].Longitude) / (Polygon[j].Longitude - Polygon[i].Longitude) + Polygon[i].Latitude) | |||
{ | |||
inside = !inside; | |||
} | |||
} | |||
return inside; | |||
} | |||
} | |||
} |
@ -0,0 +1,25 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
using Microsoft.AspNetCore.Builder; | |||
using Microsoft.AspNetCore.Hosting; | |||
namespace Microsoft.eShopOnContainers.Services.Locations.API | |||
{ | |||
public class Program | |||
{ | |||
public static void Main(string[] args) | |||
{ | |||
var host = new WebHostBuilder() | |||
.UseKestrel() | |||
.UseContentRoot(Directory.GetCurrentDirectory()) | |||
.UseStartup<Startup>() | |||
.UseApplicationInsights() | |||
.Build(); | |||
host.Run(); | |||
} | |||
} | |||
} |
@ -0,0 +1,29 @@ | |||
{ | |||
"iisSettings": { | |||
"windowsAuthentication": false, | |||
"anonymousAuthentication": true, | |||
"iisExpress": { | |||
"applicationUrl": "http://localhost:3278/", | |||
"sslPort": 0 | |||
} | |||
}, | |||
"profiles": { | |||
"IIS Express": { | |||
"commandName": "IISExpress", | |||
"launchBrowser": true, | |||
"launchUrl": "api/values", | |||
"environmentVariables": { | |||
"ASPNETCORE_ENVIRONMENT": "Development" | |||
} | |||
}, | |||
"Locations.API": { | |||
"commandName": "Project", | |||
"launchBrowser": true, | |||
"launchUrl": "api/values", | |||
"environmentVariables": { | |||
"ASPNETCORE_ENVIRONMENT": "Development" | |||
}, | |||
"applicationUrl": "http://localhost:3279" | |||
} | |||
} | |||
} |
@ -0,0 +1,115 @@ | |||
using Microsoft.AspNetCore.Builder; | |||
using Microsoft.AspNetCore.Hosting; | |||
using Microsoft.EntityFrameworkCore.Infrastructure; | |||
using Microsoft.EntityFrameworkCore; | |||
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure; | |||
using Microsoft.Extensions.Configuration; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Logging; | |||
using System.Reflection; | |||
using System; | |||
namespace Microsoft.eShopOnContainers.Services.Locations.API | |||
{ | |||
public class Startup | |||
{ | |||
public IConfigurationRoot Configuration { get; } | |||
public Startup(IHostingEnvironment env) | |||
{ | |||
var builder = new ConfigurationBuilder() | |||
.SetBasePath(env.ContentRootPath) | |||
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) | |||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); | |||
if (env.IsDevelopment()) | |||
{ | |||
builder.AddUserSecrets(typeof(Startup).GetTypeInfo().Assembly); | |||
} | |||
builder.AddEnvironmentVariables(); | |||
Configuration = builder.Build(); | |||
} | |||
// This method gets called by the runtime. Use this method to add services to the container. | |||
public void ConfigureServices(IServiceCollection services) | |||
{ | |||
// Add framework services. | |||
services.AddMvc(); | |||
services.AddDbContext<LocationsContext>(options => | |||
{ | |||
options.UseSqlServer(Configuration["ConnectionString"], | |||
sqlServerOptionsAction: sqlOptions => | |||
{ | |||
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); | |||
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency | |||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); | |||
}); | |||
// Changing default behavior when client evaluation occurs to throw. | |||
// Default in EF Core would be to log a warning when client evaluation is performed. | |||
options.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning)); | |||
//Check Client vs. Server evaluation: https://docs.microsoft.com/en-us/ef/core/querying/client-eval | |||
}); | |||
// Add framework services. | |||
services.AddSwaggerGen(options => | |||
{ | |||
options.DescribeAllEnumsAsStrings(); | |||
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info | |||
{ | |||
Title = "eShopOnContainers - Location HTTP API", | |||
Version = "v1", | |||
Description = "The Location Microservice HTTP API. This is a Data-Driven/CRUD microservice sample", | |||
TermsOfService = "Terms Of Service" | |||
}); | |||
}); | |||
services.AddCors(options => | |||
{ | |||
options.AddPolicy("CorsPolicy", | |||
builder => builder.AllowAnyOrigin() | |||
.AllowAnyMethod() | |||
.AllowAnyHeader() | |||
.AllowCredentials()); | |||
}); | |||
} | |||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | |||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) | |||
{ | |||
//Configure logs | |||
loggerFactory.AddConsole(Configuration.GetSection("Logging")); | |||
loggerFactory.AddDebug(); | |||
app.UseCors("CorsPolicy"); | |||
ConfigureAuth(app); | |||
app.UseMvcWithDefaultRoute(); | |||
app.UseSwagger() | |||
.UseSwaggerUI(c => | |||
{ | |||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); | |||
}); | |||
LocationsContextSeed.SeedAsync(app, loggerFactory) | |||
.Wait(); | |||
} | |||
protected virtual void ConfigureAuth(IApplicationBuilder app) | |||
{ | |||
var identityUrl = Configuration.GetValue<string>("IdentityUrl"); | |||
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions | |||
{ | |||
Authority = identityUrl.ToString(), | |||
ApiName = "locations", | |||
RequireHttpsMetadata = false | |||
}); | |||
} | |||
} | |||
} |
@ -0,0 +1,10 @@ | |||
{ | |||
"Logging": { | |||
"IncludeScopes": false, | |||
"LogLevel": { | |||
"Default": "Debug", | |||
"System": "Information", | |||
"Microsoft": "Information" | |||
} | |||
} | |||
} |
@ -0,0 +1,12 @@ | |||
{ | |||
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.LocationsDb;User Id=sa;Password=Pass@word;", | |||
"IdentityUrl": "http://localhost:5105", | |||
"Logging": { | |||
"IncludeScopes": false, | |||
"LogLevel": { | |||
"Default": "Debug", | |||
"System": "Information", | |||
"Microsoft": "Information" | |||
} | |||
} | |||
} |