@ -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" | |||||
} | |||||
} | |||||
} |