Merge branch 'feature/track-user-location-mongodb' of https://github.com/dotnet-architecture/eShopOnContainers into LocationSettingsXamarin
This commit is contained in:
commit
9c3ad2b2d2
@ -83,6 +83,10 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "5433:1433"
|
- "5433:1433"
|
||||||
|
|
||||||
|
nosql.data:
|
||||||
|
ports:
|
||||||
|
- "27017:27017"
|
||||||
|
|
||||||
webstatus:
|
webstatus:
|
||||||
environment:
|
environment:
|
||||||
- ASPNETCORE_ENVIRONMENT=Development
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
@ -100,7 +104,8 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- ASPNETCORE_ENVIRONMENT=Development
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
- ASPNETCORE_URLS=http://0.0.0.0:80
|
- ASPNETCORE_URLS=http://0.0.0.0:80
|
||||||
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.LocationsDb;User Id=sa;Password=Pass@word
|
- ConnectionString=mongodb://nosql.data
|
||||||
|
- Database=LocationsDb
|
||||||
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
|
- identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
|
||||||
- EventBusConnection=rabbitmq
|
- EventBusConnection=rabbitmq
|
||||||
ports:
|
ports:
|
||||||
|
@ -59,6 +59,9 @@ services:
|
|||||||
sql.data:
|
sql.data:
|
||||||
image: microsoft/mssql-server-linux
|
image: microsoft/mssql-server-linux
|
||||||
|
|
||||||
|
nosql.data:
|
||||||
|
image: mongo
|
||||||
|
|
||||||
basket.data:
|
basket.data:
|
||||||
image: redis
|
image: redis
|
||||||
ports:
|
ports:
|
||||||
@ -81,4 +84,4 @@ services:
|
|||||||
context: ./src/Services/Location/Locations.API
|
context: ./src/Services/Location/Locations.API
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
depends_on:
|
depends_on:
|
||||||
- sql.data
|
- nosql.data
|
@ -20,6 +20,24 @@ namespace Locations.API.Controllers
|
|||||||
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
|
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GET api/v1/[controller]/1
|
||||||
|
[Route("{userId:int}")]
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetUserLocation(int userId)
|
||||||
|
{
|
||||||
|
var userLocation = await _locationsService.GetUserLocation(userId);
|
||||||
|
return Ok(userLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
//GET api/v1/[controller]/locations
|
||||||
|
[Route("locations")]
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetAllLocations()
|
||||||
|
{
|
||||||
|
var userLocation = await _locationsService.GetAllLocation();
|
||||||
|
return Ok(userLocation);
|
||||||
|
}
|
||||||
|
|
||||||
//POST api/v1/[controller]/
|
//POST api/v1/[controller]/
|
||||||
[Route("")]
|
[Route("")]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.ActionResults
|
||||||
|
{
|
||||||
|
public class InternalServerErrorObjectResult : ObjectResult
|
||||||
|
{
|
||||||
|
public InternalServerErrorObjectResult(object error)
|
||||||
|
: base(error)
|
||||||
|
{
|
||||||
|
StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Exceptions
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exception type for app exceptions
|
||||||
|
/// </summary>
|
||||||
|
public class LocationDomainException : Exception
|
||||||
|
{
|
||||||
|
public LocationDomainException()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public LocationDomainException(string message)
|
||||||
|
: base(message)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public LocationDomainException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Filters
|
||||||
|
{
|
||||||
|
using AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.ActionResults;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Exceptions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
public class HttpGlobalExceptionFilter : IExceptionFilter
|
||||||
|
{
|
||||||
|
private readonly IHostingEnvironment env;
|
||||||
|
private readonly ILogger<HttpGlobalExceptionFilter> logger;
|
||||||
|
|
||||||
|
public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger<HttpGlobalExceptionFilter> logger)
|
||||||
|
{
|
||||||
|
this.env = env;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnException(ExceptionContext context)
|
||||||
|
{
|
||||||
|
logger.LogError(new EventId(context.Exception.HResult),
|
||||||
|
context.Exception,
|
||||||
|
context.Exception.Message);
|
||||||
|
|
||||||
|
if (context.Exception.GetType() == typeof(LocationDomainException))
|
||||||
|
{
|
||||||
|
var json = new JsonErrorResponse
|
||||||
|
{
|
||||||
|
Messages = new[] { context.Exception.Message }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Result asigned to a result object but in destiny the response is empty. This is a known bug of .net core 1.1
|
||||||
|
//It will be fixed in .net core 1.1.2. See https://github.com/aspnet/Mvc/issues/5594 for more information
|
||||||
|
context.Result = new BadRequestObjectResult(json);
|
||||||
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var json = new JsonErrorResponse
|
||||||
|
{
|
||||||
|
Messages = new[] { "An error occur.Try it again." }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
json.DeveloperMessage = context.Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result asigned to a result object but in destiny the response is empty. This is a known bug of .net core 1.1
|
||||||
|
// It will be fixed in .net core 1.1.2. See https://github.com/aspnet/Mvc/issues/5594 for more information
|
||||||
|
context.Result = new InternalServerErrorObjectResult(json);
|
||||||
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||||
|
}
|
||||||
|
context.ExceptionHandled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class JsonErrorResponse
|
||||||
|
{
|
||||||
|
public string[] Messages { get; set; }
|
||||||
|
|
||||||
|
public object DeveloperMessage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,72 +1,34 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure
|
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure
|
||||||
{
|
{
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
|
||||||
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories;
|
|
||||||
using Microsoft.eShopOnContainers.Services.Locations.API.Model;
|
using Microsoft.eShopOnContainers.Services.Locations.API.Model;
|
||||||
using System.Threading;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Threading.Tasks;
|
using MongoDB.Driver;
|
||||||
|
|
||||||
public class LocationsContext : DbContext, IUnitOfWork
|
public class LocationsContext
|
||||||
{
|
{
|
||||||
public LocationsContext(DbContextOptions options) : base(options)
|
private readonly IMongoDatabase _database = null;
|
||||||
|
|
||||||
|
public LocationsContext(IOptions<LocationSettings> settings)
|
||||||
{
|
{
|
||||||
|
var client = new MongoClient(settings.Value.ConnectionString);
|
||||||
|
if (client != null)
|
||||||
|
_database = client.GetDatabase(settings.Value.Database);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbSet<Locations> Locations { get; set; }
|
public IMongoCollection<UserLocation> UserLocation
|
||||||
public DbSet<FrontierPoints> FrontierPoints { get; set; }
|
|
||||||
public DbSet<UserLocation> UserLocation { get; set; }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder builder)
|
|
||||||
{
|
{
|
||||||
builder.Entity<Locations>(ConfigureLocations);
|
get
|
||||||
builder.Entity<FrontierPoints>(ConfigureFrontierPoints);
|
{
|
||||||
builder.Entity<UserLocation>(ConfigureUserLocation);
|
return _database.GetCollection<UserLocation>("UserLocation");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureLocations(EntityTypeBuilder<Locations> builder)
|
public IMongoCollection<Locations> Locations
|
||||||
{
|
{
|
||||||
builder.ToTable("Locations");
|
get
|
||||||
|
{
|
||||||
builder.HasKey(cl => cl.Id);
|
return _database.GetCollection<Locations>("Locations");
|
||||||
|
}
|
||||||
builder.Property(cl => cl.Id)
|
}
|
||||||
.ForSqlServerUseSequenceHiLo("locations_seq")
|
|
||||||
.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_seq")
|
|
||||||
.IsRequired();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigureUserLocation(EntityTypeBuilder<UserLocation> builder)
|
|
||||||
{
|
|
||||||
builder.ToTable("UserLocation");
|
|
||||||
|
|
||||||
builder.Property(ul => ul.Id)
|
|
||||||
.ForSqlServerUseSequenceHiLo("UserLocation_seq")
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
builder.HasIndex(ul => ul.UserId).IsUnique();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,131 +1,123 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure
|
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure
|
||||||
{
|
{
|
||||||
using Microsoft.AspNetCore.Builder;
|
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 Microsoft.eShopOnContainers.Services.Locations.API.Model;
|
||||||
using System.Text;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
using MongoDB.Driver.GeoJsonObjectModel;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
public class LocationsContextSeed
|
public class LocationsContextSeed
|
||||||
{
|
{
|
||||||
|
private static LocationsContext ctx;
|
||||||
public static async Task SeedAsync(IApplicationBuilder applicationBuilder, ILoggerFactory loggerFactory)
|
public static async Task SeedAsync(IApplicationBuilder applicationBuilder, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
var context = (LocationsContext)applicationBuilder
|
var config = applicationBuilder
|
||||||
.ApplicationServices.GetService(typeof(LocationsContext));
|
.ApplicationServices.GetRequiredService<IOptions<LocationSettings>>();
|
||||||
|
|
||||||
context.Database.Migrate();
|
ctx = new LocationsContext(config);
|
||||||
|
|
||||||
if (!context.Locations.Any())
|
if (!ctx.Locations.Database.GetCollection<Locations>(nameof(Locations)).AsQueryable().Any())
|
||||||
{
|
{
|
||||||
context.Locations.AddRange(
|
await SetIndexes();
|
||||||
GetPreconfiguredLocations());
|
await SetUSLocations();
|
||||||
|
}
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Locations GetPreconfiguredLocations()
|
static async Task SetUSLocations()
|
||||||
{
|
{
|
||||||
var ww = new Locations("WW", "WorldWide", -1, -1);
|
var us = new Locations()
|
||||||
ww.ChildLocations.Add(GetUSLocations());
|
{
|
||||||
return ww;
|
Code = "US",
|
||||||
|
Description = "United States"
|
||||||
|
};
|
||||||
|
us.SetLocation(-101.357386, 41.650455);
|
||||||
|
await ctx.Locations.InsertOneAsync(us);
|
||||||
|
await SetWashingtonLocations(us.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Locations GetUSLocations()
|
static async Task SetWashingtonLocations(ObjectId parentId)
|
||||||
{
|
{
|
||||||
var us = new Locations("US", "United States", 41.650455, -101.357386, GetUSPoligon());
|
var wht = new Locations()
|
||||||
us.ChildLocations.Add(GetWashingtonLocations());
|
{
|
||||||
return us;
|
Parent_Id = parentId,
|
||||||
|
Code = "WHT",
|
||||||
|
Description = "Washington"
|
||||||
|
};
|
||||||
|
wht.SetLocation(-119.542781, 47.223652);
|
||||||
|
await ctx.Locations.InsertOneAsync(wht);
|
||||||
|
await SetSeattleLocations(wht.Id);
|
||||||
|
await SetRedmondLocations(wht.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Locations GetWashingtonLocations()
|
static async Task SetSeattleLocations(ObjectId parentId)
|
||||||
{
|
{
|
||||||
var wht = new Locations("WHT", "Washington", 47.223652, -119.542781, GetWashingtonPoligon());
|
var stl = new Locations()
|
||||||
wht.ChildLocations.Add(GetSeattleLocations());
|
{
|
||||||
wht.ChildLocations.Add(GetRedmondLocations());
|
Parent_Id = parentId,
|
||||||
return wht;
|
Code = "SEAT",
|
||||||
}
|
Description = "Seattle",
|
||||||
|
Polygon = GetSeattlePoligon()
|
||||||
static Locations GetSeattleLocations()
|
};
|
||||||
{
|
stl.SetLocation(-122.330747, 47.603111);
|
||||||
var bcn = new Locations("SEAT", "Seattle", 47.603111, -122.330747, GetSeattlePoligon());
|
await ctx.Locations.InsertOneAsync(stl);
|
||||||
bcn.ChildLocations.Add(new Locations("SEAT-PioneerSqr", "Seattle Pioneer Square Shop", 47.602053, -122.333884, GetSeattlePioneerSqrPoligon()));
|
|
||||||
return bcn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Locations GetRedmondLocations()
|
static async Task SetRedmondLocations(ObjectId parentId)
|
||||||
{
|
{
|
||||||
var bcn = new Locations("REDM", "Redmond", 47.674961, -122.122887, GetRedmondPoligon());
|
var rdm = new Locations()
|
||||||
bcn.ChildLocations.Add(new Locations("REDM-DWNTWP", "Redmond Downtown Central Park Shop", 47.674433, -122.125006, GetRedmondDowntownParkPoligon()));
|
{
|
||||||
return bcn;
|
Parent_Id = parentId,
|
||||||
}
|
Code = "REDM",
|
||||||
|
Description = "Redmond",
|
||||||
static List<FrontierPoints> GetUSPoligon()
|
Polygon = GetRedmondPoligon()
|
||||||
{
|
};
|
||||||
var poligon = new List<FrontierPoints>();
|
rdm.SetLocation(-122.122887, 47.674961);
|
||||||
poligon.Add(new FrontierPoints(48.7985, -62.88205));
|
await ctx.Locations.InsertOneAsync(rdm);
|
||||||
poligon.Add(new FrontierPoints(48.76513, -129.3132));
|
|
||||||
poligon.Add(new FrontierPoints(30.12256, -120.9496));
|
|
||||||
poligon.Add(new FrontierPoints(30.87114, -111.3944));
|
|
||||||
poligon.Add(new FrontierPoints(24.24979, -78.11975));
|
|
||||||
return poligon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<FrontierPoints> GetWashingtonPoligon()
|
static async Task SetIndexes()
|
||||||
{
|
{
|
||||||
var poligon = new List<FrontierPoints>();
|
// Set location indexes
|
||||||
poligon.Add(new FrontierPoints(48.8943, -124.68633));
|
var builder = Builders<Locations>.IndexKeys;
|
||||||
poligon.Add(new FrontierPoints(45.66613, -124.32962));
|
var keys = builder.Geo2DSphere(prop => prop.Location);
|
||||||
poligon.Add(new FrontierPoints(45.93384, -116.73824));
|
await ctx.Locations.Indexes.CreateOneAsync(keys);
|
||||||
poligon.Add(new FrontierPoints(49.04282, -116.96912));
|
}
|
||||||
return poligon;
|
|
||||||
|
static GeoJsonPolygon<GeoJson2DGeographicCoordinates> GetSeattlePoligon()
|
||||||
|
{
|
||||||
|
return new GeoJsonPolygon<GeoJson2DGeographicCoordinates>(new GeoJsonPolygonCoordinates<GeoJson2DGeographicCoordinates>(
|
||||||
|
new GeoJsonLinearRingCoordinates<GeoJson2DGeographicCoordinates>(
|
||||||
|
new List<GeoJson2DGeographicCoordinates>()
|
||||||
|
{
|
||||||
|
new GeoJson2DGeographicCoordinates(-122.36238,47.82929),
|
||||||
|
new GeoJson2DGeographicCoordinates(-122.42091,47.6337),
|
||||||
|
new GeoJson2DGeographicCoordinates(-122.37371,47.45224),
|
||||||
|
new GeoJson2DGeographicCoordinates(-122.20788,47.50259),
|
||||||
|
new GeoJson2DGeographicCoordinates(-122.26934,47.73644),
|
||||||
|
new GeoJson2DGeographicCoordinates(-122.36238,47.82929)
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<FrontierPoints> GetSeattlePoligon()
|
static GeoJsonPolygon<GeoJson2DGeographicCoordinates> GetRedmondPoligon()
|
||||||
{
|
{
|
||||||
var poligon = new List<FrontierPoints>();
|
return new GeoJsonPolygon<GeoJson2DGeographicCoordinates>(new GeoJsonPolygonCoordinates<GeoJson2DGeographicCoordinates>(
|
||||||
poligon.Add(new FrontierPoints(47.82929, -122.36238));
|
new GeoJsonLinearRingCoordinates<GeoJson2DGeographicCoordinates>(
|
||||||
poligon.Add(new FrontierPoints(47.6337, -122.42091));
|
new List<GeoJson2DGeographicCoordinates>()
|
||||||
poligon.Add(new FrontierPoints(47.45224, -122.37371));
|
{
|
||||||
poligon.Add(new FrontierPoints(47.50259, -122.20788));
|
new GeoJson2DGeographicCoordinates(47.73148, -122.15432),
|
||||||
poligon.Add(new FrontierPoints(47.73644, -122.26934));
|
new GeoJson2DGeographicCoordinates(47.72559, -122.17673),
|
||||||
return poligon;
|
new GeoJson2DGeographicCoordinates(47.67851, -122.16904),
|
||||||
}
|
new GeoJson2DGeographicCoordinates(47.65036, -122.16136),
|
||||||
|
new GeoJson2DGeographicCoordinates(47.62746, -122.15604),
|
||||||
static List<FrontierPoints> GetRedmondPoligon()
|
new GeoJson2DGeographicCoordinates(47.63463, -122.01562),
|
||||||
{
|
new GeoJson2DGeographicCoordinates(47.74244, -122.04961),
|
||||||
var poligon = new List<FrontierPoints>();
|
new GeoJson2DGeographicCoordinates(47.73148, -122.15432),
|
||||||
poligon.Add(new FrontierPoints(47.73148, -122.15432));
|
})));
|
||||||
poligon.Add(new FrontierPoints(47.72559, -122.17673));
|
}
|
||||||
poligon.Add(new FrontierPoints(47.67851, -122.16904));
|
|
||||||
poligon.Add(new FrontierPoints(47.65036, -122.16136));
|
|
||||||
poligon.Add(new FrontierPoints(47.62746, -122.15604));
|
|
||||||
poligon.Add(new FrontierPoints(47.63463, -122.01562));
|
|
||||||
poligon.Add(new FrontierPoints(47.74244, -122.04961));
|
|
||||||
return poligon;
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<FrontierPoints> GetSeattlePioneerSqrPoligon()
|
|
||||||
{
|
|
||||||
var poligon = new List<FrontierPoints>();
|
|
||||||
poligon.Add(new FrontierPoints(47.60338, -122.3327));
|
|
||||||
poligon.Add(new FrontierPoints(47.60192, -122.33665));
|
|
||||||
poligon.Add(new FrontierPoints(47.60096, -122.33456));
|
|
||||||
poligon.Add(new FrontierPoints(47.60136, -122.33186));
|
|
||||||
return poligon;
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<FrontierPoints> GetRedmondDowntownParkPoligon()
|
|
||||||
{
|
|
||||||
var poligon = new List<FrontierPoints>();
|
|
||||||
poligon.Add(new FrontierPoints(47.67595, -122.12467));
|
|
||||||
poligon.Add(new FrontierPoints(47.67449, -122.12862));
|
|
||||||
poligon.Add(new FrontierPoints(47.67353, -122.12653));
|
|
||||||
poligon.Add(new FrontierPoints(47.67368, -122.12197));
|
|
||||||
return poligon;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
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("20170601140634_Initial")]
|
|
||||||
partial class Initial
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "1.1.2")
|
|
||||||
.HasAnnotation("SqlServer:Sequence:.frontier_seq", "'frontier_seq', '', '1', '10', '', '', 'Int64', 'False'")
|
|
||||||
.HasAnnotation("SqlServer:Sequence:.locations_seq", "'locations_seq', '', '1', '10', '', '', 'Int64', 'False'")
|
|
||||||
.HasAnnotation("SqlServer:Sequence:.UserLocation_seq", "'UserLocation_seq', '', '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_seq")
|
|
||||||
.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_seq")
|
|
||||||
.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.UserLocation", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasAnnotation("SqlServer:HiLoSequenceName", "UserLocation_seq")
|
|
||||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
|
||||||
|
|
||||||
b.Property<int?>("LocationId");
|
|
||||||
|
|
||||||
b.Property<int>("UserId");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("LocationId");
|
|
||||||
|
|
||||||
b.HasIndex("UserId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("UserLocation");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.FrontierPoints", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations", "Location")
|
|
||||||
.WithMany("Polygon")
|
|
||||||
.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");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.UserLocation", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations", "Location")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("LocationId");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,152 +0,0 @@
|
|||||||
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_seq",
|
|
||||||
incrementBy: 10);
|
|
||||||
|
|
||||||
migrationBuilder.CreateSequence(
|
|
||||||
name: "locations_seq",
|
|
||||||
incrementBy: 10);
|
|
||||||
|
|
||||||
migrationBuilder.CreateSequence(
|
|
||||||
name: "UserLocation_seq",
|
|
||||||
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.CreateTable(
|
|
||||||
name: "UserLocation",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(nullable: false),
|
|
||||||
LocationId = table.Column<int>(nullable: true),
|
|
||||||
UserId = table.Column<int>(nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_UserLocation", x => x.Id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_UserLocation_Locations_LocationId",
|
|
||||||
column: x => x.LocationId,
|
|
||||||
principalTable: "Locations",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Restrict);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_FrontierPoints_LocationId",
|
|
||||||
table: "FrontierPoints",
|
|
||||||
column: "LocationId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Locations_ParentId",
|
|
||||||
table: "Locations",
|
|
||||||
column: "ParentId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_UserLocation_LocationId",
|
|
||||||
table: "UserLocation",
|
|
||||||
column: "LocationId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_UserLocation_UserId",
|
|
||||||
table: "UserLocation",
|
|
||||||
column: "UserId",
|
|
||||||
unique: true);
|
|
||||||
|
|
||||||
migrationBuilder.Sql(CreateGetDistanceFunction());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "FrontierPoints");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "UserLocation");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Locations");
|
|
||||||
|
|
||||||
migrationBuilder.DropSequence(
|
|
||||||
name: "frontier_seq");
|
|
||||||
|
|
||||||
migrationBuilder.DropSequence(
|
|
||||||
name: "locations_seq");
|
|
||||||
|
|
||||||
migrationBuilder.DropSequence(
|
|
||||||
name: "UserLocation_seq");
|
|
||||||
|
|
||||||
migrationBuilder.Sql(@"DROP FUNCTION IF EXISTS dbo.GetDistanceFromLocation");
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
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_seq", "'frontier_seq', '', '1', '10', '', '', 'Int64', 'False'")
|
|
||||||
.HasAnnotation("SqlServer:Sequence:.locations_seq", "'locations_seq', '', '1', '10', '', '', 'Int64', 'False'")
|
|
||||||
.HasAnnotation("SqlServer:Sequence:.UserLocation_seq", "'UserLocation_seq', '', '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_seq")
|
|
||||||
.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_seq")
|
|
||||||
.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.UserLocation", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasAnnotation("SqlServer:HiLoSequenceName", "UserLocation_seq")
|
|
||||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
|
||||||
|
|
||||||
b.Property<int?>("LocationId");
|
|
||||||
|
|
||||||
b.Property<int>("UserId");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("LocationId");
|
|
||||||
|
|
||||||
b.HasIndex("UserId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("UserLocation");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.FrontierPoints", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations", "Location")
|
|
||||||
.WithMany("Polygon")
|
|
||||||
.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");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Locations.API.Model.UserLocation", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Microsoft.eShopOnContainers.Services.Locations.API.Model.Locations", "Location")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("LocationId");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +1,25 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories
|
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories
|
||||||
{
|
{
|
||||||
using Microsoft.eShopOnContainers.Services.Locations.API.Model;
|
using Microsoft.eShopOnContainers.Services.Locations.API.Model;
|
||||||
|
using MongoDB.Bson;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
public interface ILocationsRepository : IRepository
|
public interface ILocationsRepository
|
||||||
{
|
{
|
||||||
UserLocation Add(UserLocation order);
|
Task<Locations> GetAsync(ObjectId locationId);
|
||||||
|
|
||||||
void Update(UserLocation order);
|
Task<List<Locations>> GetLocationListAsync();
|
||||||
|
|
||||||
Task<UserLocation> GetAsync(int userId);
|
Task<UserLocation> GetUserLocationAsync(int userId);
|
||||||
|
|
||||||
Task<List<Locations>> GetNearestLocationListAsync(double lat, double lon);
|
Task<List<Locations>> GetNearestLocationListAsync(double lat, double lon);
|
||||||
|
|
||||||
|
Task<Locations> GetLocationByCurrentAreaAsync(Locations location);
|
||||||
|
|
||||||
|
Task AddUserLocationAsync(UserLocation location);
|
||||||
|
|
||||||
|
Task UpdateUserLocationAsync(UserLocation userLocation);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories
|
|
||||||
{
|
|
||||||
public interface IRepository
|
|
||||||
{
|
|
||||||
IUnitOfWork UnitOfWork { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories
|
|
||||||
{
|
|
||||||
public interface IUnitOfWork : IDisposable
|
|
||||||
{
|
|
||||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,54 +7,67 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
using MongoDB.Driver.GeoJsonObjectModel;
|
||||||
|
using MongoDB.Driver.Builders;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
|
||||||
public class LocationsRepository
|
public class LocationsRepository
|
||||||
: ILocationsRepository
|
: ILocationsRepository
|
||||||
{
|
{
|
||||||
private readonly LocationsContext _context;
|
private readonly LocationsContext _context;
|
||||||
|
|
||||||
public IUnitOfWork UnitOfWork
|
public LocationsRepository(IOptions<LocationSettings> settings)
|
||||||
{
|
{
|
||||||
get
|
_context = new LocationsContext(settings);
|
||||||
{
|
}
|
||||||
return _context;
|
|
||||||
}
|
public async Task<Locations> GetAsync(ObjectId locationId)
|
||||||
|
{
|
||||||
|
var filter = Builders<Locations>.Filter.Eq("Id", locationId);
|
||||||
|
return await _context.Locations
|
||||||
|
.Find(filter)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocationsRepository(LocationsContext context)
|
public async Task<UserLocation> GetUserLocationAsync(int userId)
|
||||||
{
|
|
||||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserLocation Add(UserLocation location)
|
|
||||||
{
|
|
||||||
return _context.UserLocation.Add(location).Entity;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<UserLocation> GetAsync(int userId)
|
|
||||||
{
|
{
|
||||||
|
var filter = Builders<UserLocation>.Filter.Eq("UserId", userId);
|
||||||
return await _context.UserLocation
|
return await _context.UserLocation
|
||||||
.Where(ul => ul.UserId == userId)
|
.Find(filter)
|
||||||
.SingleOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<Locations>> GetLocationListAsync()
|
||||||
|
{
|
||||||
|
return await _context.Locations.Find(new BsonDocument()).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<List<Locations>> GetNearestLocationListAsync(double lat, double lon)
|
public async Task<List<Locations>> GetNearestLocationListAsync(double lat, double lon)
|
||||||
{
|
{
|
||||||
var query = $"SELECT TOP(100) location.* " +
|
var point = GeoJson.Point(GeoJson.Geographic(lon, lat));
|
||||||
$"FROM[dbo].[Locations] AS location " +
|
var query = new FilterDefinitionBuilder<Locations>().Near(x => x.Location, point);
|
||||||
$"ORDER BY [dbo].[GetDistanceFromLocation](location.Latitude, location.Longitude, " +
|
return await _context.Locations.Find(query).ToListAsync();
|
||||||
$"{lat.ToString(CultureInfo.InvariantCulture)}, " +
|
|
||||||
$"{lon.ToString(CultureInfo.InvariantCulture)})";
|
|
||||||
|
|
||||||
return await _context.Locations.FromSql(query)
|
|
||||||
.Include(f => f.Polygon)
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(UserLocation location)
|
public async Task<Locations> GetLocationByCurrentAreaAsync(Locations location)
|
||||||
{
|
{
|
||||||
_context.Entry(location).State = EntityState.Modified;
|
var query = new FilterDefinitionBuilder<Locations>().GeoIntersects("Location", location.Polygon);
|
||||||
|
return await _context.Locations.Find(query).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddUserLocationAsync(UserLocation location)
|
||||||
|
{
|
||||||
|
await _context.UserLocation.InsertOneAsync(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateUserLocationAsync(UserLocation userLocation)
|
||||||
|
{
|
||||||
|
await _context.UserLocation.ReplaceOneAsync(
|
||||||
|
doc => doc.UserId == userLocation.UserId,
|
||||||
|
userLocation,
|
||||||
|
new UpdateOptions { IsUpsert = true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Services
|
namespace Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Services
|
||||||
{
|
{
|
||||||
|
using Microsoft.eShopOnContainers.Services.Locations.API.Model;
|
||||||
using Microsoft.eShopOnContainers.Services.Locations.API.ViewModel;
|
using Microsoft.eShopOnContainers.Services.Locations.API.ViewModel;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
public interface ILocationsService
|
public interface ILocationsService
|
||||||
{
|
{
|
||||||
|
Task<UserLocation> GetUserLocation(int id);
|
||||||
|
|
||||||
|
Task<List<Locations>> GetAllLocation();
|
||||||
|
|
||||||
Task<bool> AddOrUpdateUserLocation(string userId, LocationRequest locRequest);
|
Task<bool> AddOrUpdateUserLocation(string userId, LocationRequest locRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Locations.API.Model;
|
using Microsoft.eShopOnContainers.Services.Locations.API.Model;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Exceptions;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public class LocationsService : ILocationsService
|
public class LocationsService : ILocationsService
|
||||||
{
|
{
|
||||||
@ -15,48 +18,53 @@
|
|||||||
_locationsRepository = locationsRepository ?? throw new ArgumentNullException(nameof(locationsRepository));
|
_locationsRepository = locationsRepository ?? throw new ArgumentNullException(nameof(locationsRepository));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<UserLocation> GetUserLocation(int id)
|
||||||
|
{
|
||||||
|
return await _locationsRepository.GetUserLocationAsync(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Locations>> GetAllLocation()
|
||||||
|
{
|
||||||
|
return await _locationsRepository.GetLocationListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> AddOrUpdateUserLocation(string id, LocationRequest currentPosition)
|
public async Task<bool> AddOrUpdateUserLocation(string id, LocationRequest currentPosition)
|
||||||
{
|
{
|
||||||
int.TryParse(id, out int userId);
|
Locations currentUserAreaLocation = null;
|
||||||
var currentUserLocation = await _locationsRepository.GetAsync(userId);
|
|
||||||
|
if (!int.TryParse(id, out int userId))
|
||||||
// Get the nearest locations ordered by proximity
|
{
|
||||||
|
throw new ArgumentException("Not valid userId");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the nearest locations ordered
|
||||||
var nearestLocationList = await _locationsRepository.GetNearestLocationListAsync(currentPosition.Latitude, currentPosition.Longitude);
|
var nearestLocationList = await _locationsRepository.GetNearestLocationListAsync(currentPosition.Latitude, currentPosition.Longitude);
|
||||||
|
|
||||||
// Check out in which region we currently are
|
// Check out in which region we currently are
|
||||||
foreach(var locCandidate in nearestLocationList)
|
foreach(var locationCandidate in nearestLocationList.Where(x=> x.Polygon != null))
|
||||||
{
|
{
|
||||||
// Check location's tree and retrive user most specific area
|
currentUserAreaLocation = await _locationsRepository.GetLocationByCurrentAreaAsync(locationCandidate);
|
||||||
var findNewLocationResult = locCandidate.GetUserMostSpecificLocation(currentPosition.Latitude, currentPosition.Longitude);
|
if(currentUserAreaLocation != null) { break; }
|
||||||
if (findNewLocationResult.isSuccess)
|
|
||||||
{
|
|
||||||
CreateUserLocation(currentUserLocation, findNewLocationResult.location, userId);
|
|
||||||
UpdateUserLocation(currentUserLocation, findNewLocationResult.location);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await _locationsRepository.UnitOfWork.SaveChangesAsync();
|
if(currentUserAreaLocation is null)
|
||||||
return result > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateUserLocation(UserLocation currentUserLocation, Locations newLocation, int userId)
|
|
||||||
{
|
|
||||||
if (currentUserLocation is null)
|
|
||||||
{
|
{
|
||||||
currentUserLocation = currentUserLocation ?? new UserLocation(userId);
|
throw new LocationDomainException("User current area not found");
|
||||||
currentUserLocation.Location = newLocation;
|
}
|
||||||
_locationsRepository.Add(currentUserLocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateUserLocation(UserLocation currentUserLocation, Locations newLocation)
|
// If current area found, then update user location
|
||||||
{
|
if(currentUserAreaLocation != null)
|
||||||
if (currentUserLocation != null)
|
|
||||||
{
|
{
|
||||||
currentUserLocation.Location = newLocation;
|
var locationAncestors = new List<string>();
|
||||||
_locationsRepository.Update(currentUserLocation);
|
var userLocation = await _locationsRepository.GetUserLocationAsync(userId);
|
||||||
}
|
userLocation = userLocation ?? new UserLocation();
|
||||||
|
userLocation.UserId = userId;
|
||||||
|
userLocation.LocationId = currentUserAreaLocation.Id;
|
||||||
|
userLocation.UpdateDate = DateTime.UtcNow;
|
||||||
|
await _locationsRepository.UpdateUserLocationAsync(userLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
src/Services/Location/Locations.API/LocationSettings.cs
Normal file
15
src/Services/Location/Locations.API/LocationSettings.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Services.Locations.API
|
||||||
|
{
|
||||||
|
public class LocationSettings
|
||||||
|
{
|
||||||
|
public string ExternalCatalogBaseUrl { get; set; }
|
||||||
|
public string EventBusConnection { get; set; }
|
||||||
|
public string ConnectionString { get; set; }
|
||||||
|
public string Database { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -7,9 +7,6 @@
|
|||||||
<UserSecretsId>aspnet-Locations.API-20161122013619</UserSecretsId>
|
<UserSecretsId>aspnet-Locations.API-20161122013619</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Infrastructure\Migrations\" />
|
|
||||||
<Folder Include="Infrastructure\Migrations\" />
|
|
||||||
<Folder Include="Infrastructure\Migrations\" />
|
|
||||||
<Folder Include="wwwroot\" />
|
<Folder Include="wwwroot\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -28,6 +25,10 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" 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" Version="1.1.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" />
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" />
|
||||||
|
<PackageReference Include="mongocsharpdriver" Version="2.4.3" />
|
||||||
|
<PackageReference Include="MongoDB.Bson" Version="2.4.3" />
|
||||||
|
<PackageReference Include="MongoDB.Driver" Version="2.4.3" />
|
||||||
|
<PackageReference Include="MongoDB.Driver.Core" Version="2.4.3" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Model
|
|
||||||
{
|
|
||||||
public class FrontierPoints
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public double Latitude { get; private set; }
|
|
||||||
public double Longitude { get; private set; }
|
|
||||||
|
|
||||||
public FrontierPoints()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public FrontierPoints(double latitude, double longitude)
|
|
||||||
{
|
|
||||||
Latitude = latitude;
|
|
||||||
Longitude = longitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Locations Location { get; private set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +1,27 @@
|
|||||||
using System;
|
namespace Microsoft.eShopOnContainers.Services.Locations.API.Model
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Model
|
|
||||||
{
|
{
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Driver.GeoJsonObjectModel;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public class Locations
|
public class Locations
|
||||||
{
|
{
|
||||||
public int Id { get; private set; }
|
public ObjectId Id { get; set; }
|
||||||
public string Code { get; private set; }
|
public string Code { get; set; }
|
||||||
public int? ParentId { get; private set; }
|
public ObjectId Parent_Id { get; set; }
|
||||||
public string Description { get; private set; }
|
public string Description { get; set; }
|
||||||
public double Latitude { get; private set; }
|
public double Latitude { get; set; }
|
||||||
public double Longitude { get; private set; }
|
public double Longitude { get; set; }
|
||||||
public (Locations location, bool isSuccess) GetUserMostSpecificLocation(double userLatitude, double userLongitude)
|
public GeoJsonPoint<GeoJson2DGeographicCoordinates> Location { get; set; }
|
||||||
=> CheckUserMostSpecificLocation(userLatitude, userLongitude);
|
public GeoJsonPolygon<GeoJson2DGeographicCoordinates> Polygon { get; set; }
|
||||||
|
public void SetLocation(double lon, double lat) => SetPosition(lon, lat);
|
||||||
|
|
||||||
public Locations()
|
private void SetPosition(double lon, double lat)
|
||||||
{
|
{
|
||||||
ChildLocations = new List<Locations>();
|
Latitude = lat;
|
||||||
}
|
Longitude = lon;
|
||||||
|
Location = new GeoJsonPoint<GeoJson2DGeographicCoordinates>(
|
||||||
public Locations(string code, string description, double latitude, double longitude, List<FrontierPoints> polygon = null) : this()
|
new GeoJson2DGeographicCoordinates(lon, lat));
|
||||||
{
|
|
||||||
Code = code;
|
|
||||||
Description = description;
|
|
||||||
Latitude = latitude;
|
|
||||||
Longitude = longitude;
|
|
||||||
Polygon = polygon ?? new List<FrontierPoints>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual List<FrontierPoints> Polygon { get; set; }
|
|
||||||
|
|
||||||
[ForeignKey("ParentId")]
|
|
||||||
public virtual List<Locations> ChildLocations { get; set; }
|
|
||||||
|
|
||||||
private (Locations location, bool isSuccess) CheckUserMostSpecificLocation(double userLatitude, double userLongitude, Locations location = null)
|
|
||||||
{
|
|
||||||
Locations result = this;
|
|
||||||
var childLocations = location != null ? location.ChildLocations : ChildLocations;
|
|
||||||
|
|
||||||
// Check if user is in location's area, if not then returns false
|
|
||||||
if (!CheckIsPointInPolygon(userLatitude, userLongitude))
|
|
||||||
{
|
|
||||||
return (this, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var childLocation in childLocations)
|
|
||||||
{
|
|
||||||
result = childLocation;
|
|
||||||
|
|
||||||
if (childLocation.ChildLocations.Count == 0){ break; }
|
|
||||||
|
|
||||||
CheckUserMostSpecificLocation(userLatitude, userLongitude, childLocation);
|
|
||||||
}
|
|
||||||
return (result, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CheckIsPointInPolygon(double lat, double lon)
|
|
||||||
{
|
|
||||||
if(Polygon.Count == 0) { return false; };
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,16 @@
|
|||||||
using System;
|
namespace Microsoft.eShopOnContainers.Services.Locations.API.Model
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Locations.API.Model
|
|
||||||
{
|
{
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
using MongoDB.Bson;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public class UserLocation
|
public class UserLocation
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
[BsonIgnoreIfDefault]
|
||||||
public int UserId { get; set; }
|
public ObjectId Id { get; set; }
|
||||||
|
public int UserId { get; set; } = 0;
|
||||||
public UserLocation()
|
public ObjectId LocationId { get; set; }
|
||||||
{
|
public DateTime UpdateDate { get; set; }
|
||||||
}
|
|
||||||
|
|
||||||
public UserLocation(int userId) : this()
|
|
||||||
{
|
|
||||||
UserId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Locations Location { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ using System;
|
|||||||
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Services;
|
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Services;
|
||||||
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories;
|
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Filters;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Locations.API
|
namespace Microsoft.eShopOnContainers.Services.Locations.API
|
||||||
{
|
{
|
||||||
@ -39,24 +40,13 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API
|
|||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
// Add framework services.
|
// Add framework services.
|
||||||
services.AddMvc();
|
services.AddMvc(options =>
|
||||||
|
|
||||||
services.AddDbContext<LocationsContext>(options =>
|
|
||||||
{
|
{
|
||||||
options.UseSqlServer(Configuration["ConnectionString"],
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
sqlServerOptionsAction: sqlOptions =>
|
}).AddControllersAsServices();
|
||||||
{
|
|
||||||
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
|
|
||||||
});
|
|
||||||
|
|
||||||
|
services.Configure<LocationSettings>(Configuration);
|
||||||
|
|
||||||
// Add framework services.
|
// Add framework services.
|
||||||
services.AddSwaggerGen(options =>
|
services.AddSwaggerGen(options =>
|
||||||
{
|
{
|
||||||
@ -82,7 +72,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API
|
|||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
services.AddTransient<IIdentityService, IdentityService>();
|
services.AddTransient<IIdentityService, IdentityService>();
|
||||||
services.AddTransient<ILocationsService, LocationsService>();
|
services.AddTransient<ILocationsService, LocationsService>();
|
||||||
services.AddTransient<ILocationsRepository, LocationsRepository>();
|
services.AddTransient<ILocationsRepository, LocationsRepository>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.LocationsDb;User Id=sa;Password=Pass@word;",
|
"ConnectionString": "mongodb://nosql.data",
|
||||||
|
"Database": "LocationsDb",
|
||||||
"IdentityUrl": "http://localhost:5105",
|
"IdentityUrl": "http://localhost:5105",
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"IncludeScopes": false,
|
"IncludeScopes": false,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Locations.API.ViewModel;
|
using Microsoft.eShopOnContainers.Services.Locations.API.Model;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Locations.API.ViewModel;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -11,26 +12,37 @@ namespace IntegrationTests.Services.Locations
|
|||||||
: LocationsScenarioBase
|
: LocationsScenarioBase
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Set_new_user_location_response_ok_status_code()
|
public async Task Set_new_user_seattle_location_response_ok_status_code()
|
||||||
{
|
{
|
||||||
using (var server = CreateServer())
|
using (var server = CreateServer())
|
||||||
{
|
{
|
||||||
var content = new StringContent(BuildLocationsRequest(), UTF8Encoding.UTF8, "application/json");
|
var userId = 1234;
|
||||||
|
var content = new StringContent(BuildLocationsRequest(-122.315752, 47.604610), UTF8Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
var response = await server.CreateClient()
|
var response = await server.CreateClient()
|
||||||
.PostAsync(Post.AddNewLocation, content);
|
.PostAsync(Post.AddNewLocation, content);
|
||||||
|
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var userLocationResponse = await server.CreateClient()
|
||||||
|
.GetAsync(Get.LocationBy(userId));
|
||||||
|
|
||||||
|
var responseBody = await userLocationResponse.Content.ReadAsStringAsync();
|
||||||
|
var userLocation = JsonConvert.DeserializeObject<UserLocation>(responseBody);
|
||||||
|
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string BuildLocationsRequest()
|
string BuildLocationsRequest(double lon, double lat)
|
||||||
{
|
{
|
||||||
var location = new LocationRequest()
|
var location = new LocationRequest()
|
||||||
{
|
{
|
||||||
Longitude = -122.333875,
|
Longitude = lon,
|
||||||
Latitude = 47.602050
|
Latitude = lat
|
||||||
};
|
};
|
||||||
return JsonConvert.SerializeObject(location);
|
return JsonConvert.SerializeObject(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.LocationsDb;User Id=sa;Password=Pass@word;",
|
"ConnectionString": "mongodb://localhost:27017",
|
||||||
|
"Database": "LocationsDb",
|
||||||
"ExternalCatalogBaseUrl": "http://localhost:5101",
|
"ExternalCatalogBaseUrl": "http://localhost:5101",
|
||||||
"IdentityUrl": "http://localhost:5105",
|
"IdentityUrl": "http://localhost:5105",
|
||||||
"isTest": "true",
|
"isTest": "true",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user