ASP .NET Core: Get User IP Address - database

I have a table : with a model
public class ArticleLike:BaseEntity
{
public long? UserId { get; set; }
public string UserIp { get; set; }
public ICollection<User> User { get; set; }
}
How can I get Ipaddress of user ?
I had to write method of it on service or repository?

Get client user IP address
var remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString();
Client IP address can be retrieved via HttpContext.Connection object.
Property RemoteIpAddress is the client IP address. The returned object (System.Net.IpAddress) can be used to check whether it is IPV4 or IPV6 address.
For example, if you get a result like ::1, this is the IPv6 format

var remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress;
or
var remoteIpAddress = httpContext.GetFeature<IHttpConnectionFeature>()?.RemoteIpAddress;
Simple Usage :
In Controller
public class HomeController : Controller
{
private readonly IHttpContextAccessor _httpContextAccessor;
public HomeController(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public IActionResult Index()
{
var ip = _httpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString();
return Content(ip);
}
}
And in Startup File :
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
}

Related

asp.net core code first Cannot open database "DbName" requested by the login. The login failed

I have a asp.net core 3.1 code first project in Visual Studio 2019 and SQL Server 2017
It gives this exception when I make a request to the database:
Cannot open database "DbName" requested by the login. The login failed. Login failed for user 'sa'.
It was in Log SQL server:
Login failed for user 'NT Service\SSISScaleOutMaster150'. Reason: Could not find a login matching the name provided. [CLIENT: ]
I tried most of the solutions on the internet but none of them worked
Other info:
Named pipes are enabled
TCP/IP is enabled
Remote connections are allowed
I even removed the SQL server and reinstalled it and update Visual studio
I tried this and this but didn't work
when i create database manually the exception changed to :Invalid object name 'User'.
connection string:
"myconn": "Server=.;Database=onlineShopDB;User Id=sa;password=qazwsxedc;Trusted_Connection=False;MultipleActiveResultSets=true;"
},
configure service:
{
services.AddMvc();
services.AddDbContext<OnlineShopContext>(item => item.UseSqlServer(Configuration.GetConnectionString("myconn")));
services.AddScoped<IDataRepository<User>, UserRepository>();
services.AddControllersWithViews();
}
repositoty class:
public class UserRepository : IDataRepository<User>
{
private readonly OnlineShopContext _onlineShopContext;
public UserRepository(OnlineShopContext onlineShopContext)
{
_onlineShopContext = onlineShopContext;
}
public void Add(User entity)
{
_onlineShopContext.Users.Add(entity);
_onlineShopContext.SaveChanges();
}
}
IDataRepository:
public interface IDataRepository<TEntity>
{
IEnumerable<TEntity> GetAll();
TEntity Get(long id);
void Add(TEntity entity);
void Update(TEntity dbEntity, TEntity entity);
void Delete(TEntity entity);
}
onlineShopContext:
public class OnlineShopContext:DbContext
{
public OnlineShopContext(DbContextOptions options):base(options)
{ }
public virtual DbSet<UserType> UserTypes { get; set; }
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<Category> Categories { get; set; }
public virtual DbSet<Product> Products { get; set; }
public virtual DbSet<ProductFeatures> ProductFeatures { get; set; }
public virtual DbSet<ProductImages> GetProductImages { get; set; }
public virtual DbSet<OrderStatus> OrderStatuses { get; set; }
public virtual DbSet<Order> Orders { get; set; }
public virtual DbSet<OrderItems> OrderItems { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserType>().HasData(
new UserType() { Id = 1, Name = "User", Title = "a" },
new UserType() { Id = 2, Name = "Admin", Title = "b" });
}
}

How to change Database connection string runtime in Mobile Service TableController API

I have develop mobile app in xamarin forms and successfully login with Azure B2C. I Create a Web api using Microsoft.Azure.Mobile.Server TableController.
and it works fine.
I want to change database connection string runtime.
for example,
if (UserName == "ABC")
connectionstring = "..."
else if(UserName == "XYZ")
connectionstring = "..."
How to change Database connection string runtime in Mobile Service TableController API ?.
Freinds, I Got the solution.may be it is useful to someone.
In my MobileServiceClient API Startup.Mobile.cs, dbcontext is intialize as below
public partial class Startup
{
public async static void ConfigureMobileApp(IAppBuilder app)
{
GlobalVars.ConnectionString = #"Data Source = tcp:stronginventoryapidbserver.database.windows.net, 1433; Initial Catalog = StrongInventoryAPI_db; User ID = strong; Password=Tapsid_het1;";
Database.SetInitializer(new MigrateDatabaseToLatestVersion<ApplicationContext, StrongInventoryAPI.Migrations.Configuration>());
app.UseWebApi(config);
}
}
then, i create a ConnectionMstController to change the connection string. Below is Initailize method of Controller.
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
GlobalVars.SID = ((ClaimsPrincipal)User).FindFirst(ClaimTypes.NameIdentifier).Value;
if ( GlobalVars.SID.Contains("2e3c2d2a-14e7-4e03-bc5e-b9f6b2b09617"))
GlobalVars.ConnectionString = #"Data Source = tcp:xxxxxxxxapidbserver.database.windows.net, 1433; Initial Catalog = Drona_db; User ID = strong; Password=xxxxxx;";
ApplicationContext context = new ApplicationContext(GlobalVars.ConnectionString);
DomainManager = new EntityDomainManager<ConnectionMst>(context, Request);
}
Remember to add contructor in your context in my case Application Context. my ApplicationConext is,
public class ApplicationContext : DbContext
{
// You can add custom code to this file. Changes will not be overwritten.
//
// If you want Entity Framework to alter your database
// automatically whenever you change your model schema, please use data migrations.
// For more information refer to the documentation:
// http://msdn.microsoft.com/en-us/data/jj591621.aspx
//private const string connectionStringName = "Name=MyDbConnection";
public ApplicationContext() : base(GlobalVars.ConnectionString)
{
}
//start
public ApplicationContext(string ConnectionString) //connection string change in ConnectionMstController
: base(ConnectionString)
{
}
//end
public DbSet<ScheduleMst> ScheduleMsts { get; set; }
public DbSet<AccMst> AccMsts { get; set; }
public DbSet<ConnectionMst> ConnectionMsts { get; set; }
public DbSet<ItemGrpMst> ItemSubGrpMsts { get; set; }
public DbSet<ItemSubGrpMst> ItemSubSubGrpMsts { get; set; }
public DbSet<LotMst> LotMsts { get; set; }
public DbSet<UnitMst> UnitMsts { get; set; }
public DbSet<ItemMst> ItemMsts { get; set; }
public DbSet<SaleOrdMst> SaleOrdMsts { get; set; }
public DbSet<SaleOrdDet> SaleOrdDets { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(
new AttributeToColumnAnnotationConvention<TableColumnAttribute, string>(
"ServiceTableColumn", (property, attributes) => attributes.Single().ColumnType.ToString()));
}

how to display values from SQL database when an IP address is matched

..What Method I'm using..
I'm creating UWP app connecting to a SQL Server database via WebService.
..What I need help with..
I want to display values from the Database when the IP address matches the PC the App is run on.
..What I have so far..
Right now I have the code beyond to grab PC's local HostName show below. Might need to move it to Appx, have not decided. I also have Values displaying on the View called DevicePage. The DevicePageViewModel is making the call to the WebService
CodeBeyond>>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
foreach (HostName localHostName in NetworkInformation.GetHostNames())
{
if (localHostName.IPInformation != null)
{
if (localHostName.Type == HostNameType.Ipv4)
capturedHostName.Text = localHostName.ToString();
break;
}
}
}
ViewModel>>
var uriD = new Uri("http://localhost:2463/api/Devices");
HttpClient client = new HttpClient();
try
{
var JsonResponseD = await client.GetStringAsync(uriD);
var devicesResult = JsonConvert.DeserializeObject<List<Device>>(JsonResponseD);
Devices = devicesResult;
}
catch
{
MessageDialog dialog = new MessageDialog("Unable to Access WebService at this Time!");
await dialog.ShowAsync();
}
client.Dispose();
EntityFramework Model>>
public class Device
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int HostName { get; set; }
public string RouterName { get; set; }
public string DriveModel { get; set; }
public string DriveSN { get; set; }
public string OldDriveSN { get; set; }
public string Server { get; set; }
public string IP { get; set; }
public string Gateway { get; set; }
public string Hardware { get; set; }
}
What you are looking for is
Device device = devicesResult.Find(data => data.IP == capturedHostName.Text);
This should get you the Device Class with IP from your localHostName.

Json parsing in MVC 4 web api with angularjs

public partial class User
{
public System.Guid UserId { get; set; }
public Nullable<System.Guid> RoleId { get; set; }
public Nullable<long> MembershipNo { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public string Emaiil { get; set; }
public Nullable<decimal> MobileNo { get; set; }
public string Description { get; set; }
public Nullable<System.Guid> ModifiedBy { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
public virtual Role Role { get; set; }
}
This is my table in DB named Users which is associated with Roles table of DB (as you can see last virtual row at the end above)
Now My problem is simple. I'm using angulars $http.get() method to call my Web Api in MVC 4. When i call it, it gets connected and fetches desired record but it doesn't throw proper result back to .js file or controller.
At .js side I run into error. Every time, it executes .error(jsonResult,config,header,status) .
When I jump on to JsonResult, it shows me below error.
Object
ExceptionMessage: "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'."
ExceptionType: "System.InvalidOperationException"
InnerException: Object
ExceptionMessage: "Self referencing loop detected for property 'Role' with type
'System.Data.Entity.DynamicProxies.Role_82CA96EA045B1EB47E58B8FFD4472D86502EEA79837B4AE3AD705442F6236E58'.
Path 'Role.Users[0]'."
ExceptionType: "Newtonsoft.Json.JsonSerializationException"
Message: "An error has occurred."
I don't know what's wrong here. Is it json parsing error or something? if so, I've heard and read the articles that webapi in .net handles or throws json itself.
My call happens through
$http.get(apiUrl).success(function (jsonResult, header, config, status) {
debugger;
var number = parseInt(jsonResult.membershipNo) + 1;
$scope.membershipNo = "M" + number;
})
.error(function (jsonResult, header, config, status) {
debugger;
toastr.error('Something went wrong ! Contact Administrator!!!');
});
Edited:
One more thing to mention, .CS side when I fetch single cell value (from DB/table) , it gets returned back to .success() call but when i fetch particular row or all rows, it gets returned to .error() call. I'm using entity frameworkd 6.1.1. and above class is generated by EF-6.1.1.
public partial class Role
{
public Role()
{
this.Permissions = new List<Permission>();
this.Users = new List<User>();
}
public System.Guid RoleId { get; set; }
public string RoleName { get; set; }
public string Description { get; set; }
public Nullable<System.Guid> ModifiedBy { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
public virtual ICollection<Permission> Permissions { get; set; }
public virtual ICollection<User> Users { get; set; }
}
Hi you can solve that in 2 easy steps
First Step: Create globalConfig class where you can set ignoring ReferenceLoopHandling (http://james.newtonking.com/json/help/index.html?topic=html/SerializationSettings.htm) and if you crating js app you can set as well to remove xml formaters and always get return from Webapi as JSON string is usefull for debugging. So in your app_start folder add class GlobalConfig like below:
public class GlobalConfig
{
public static void CustomizeConfig(HttpConfiguration config)
{
// Remove Xml formatters. This means when we visit an endpoint from a browser,
// Instead of returning Xml, it will return Json.
//that is optional
config.Formatters.Remove(config.Formatters.XmlFormatter);
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
}
}
Second Step: In Global.asax set your custom configuration to do that please add code below to method Application_Start():
GlobalConfig.CustomizeConfig(GlobalConfiguration.Configuration);
it sounds like:
the problem is that EF is using lazy loading that is not materialized in time of constructing this, on role. EF from early version has switched lazy loading on by default.
Suggested solution
Create subset of you user class, with the parts that you really need.
=> Its bad practise to fetch too much data that you are not gonna need.

Showing specific data based on the currently logged in user

I have a question that deals with the logistics of returning rows of data in a SQL database (Entity Framework) based on the user that is logged in; I have mainly focused on desktop C# applications and while making the switch to ASP.NET MVC 4 I'm having a bit of difficulty when it comes to figuring this out (I've searched around and none of the answers seem to provide exactly what I'm looking for):
I would like to use the authorization built in to ASP.NET (MVC4), and allow users to post data about their websites (site category, url, age, etc.) with a form, and have the form store the data (using Entity Framework) to a database (called PrimaryDomainsDb) that is tied to their Id in the UserProfile table.
When the user clicks a button to show their list of domains, how can I make the application pull their list of domains (relevant rows of data) while ignoring other users rows?
Again, I'm mainly looking for the logistics and concepts (using foreign keys, for example) and psuedocode rather than actually spoonfeeding me a bunch of code.
If anyone has any best practice ideas (i.e. link the UserProfile to the PrimaryDomainDb this way, and use EF to call the rows matching their Id this way to return the rows to the View), it would be much appreciated.
Some sample code:
I currently have my PrimaryDomain code first set up like this (this doesn't have the decorators that specify min/max length, etc.):
public class PrimaryDomain
{
public virtual int Id { get; set; }
public virtual string SiteName { get; set; }
public virtual string SiteURL { get; set; }
public virtual SitePlatforms SitePlatform { get; set; }
public virtual decimal? SiteDA { get; set; }
public virtual decimal? SitePA { get; set; }
public virtual string SiteAge { get; set; }
public virtual DateTime? LastStatusUpdate { get; set; }
public virtual string SiteIP { get; set; }
}
And I have a User class that is different than the one provided by ASP.NET WebSecurity, that looks like this: (also, I know that "password" should not be in string formatting, this is just for initial set-up purposes - and password should probably be removed altogether and handled by WebSecurity, I think).
public class User
{
public virtual int Id { get; set; }
public virtual string Username { get; set; }
public virtual string Password { get; set; }
public virtual string Email { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string MozAccessID { get; set; }
public virtual string MozKey { get; set; }
public virtual decimal AccuountBalance { get; set; }
public virtual PrivateProxy PrivateProxies { get; set; }
public virtual PrimaryDomain PrimaryDomains { get; set; }
}
When pulling the data for Views I run everything through a repository using direct injection:
public interface IUserDataSource
{
IQueryable<User> Users { get; }
IQueryable<PrimaryDomain> PrimaryDomains { get; }
void Save();
}
This is my UserDb class, which is fed in whenever the code calls for an IUserDataSource (via direct injection):
public class UserDb : DbContext, IUserDataSource
{
public UserDb()
: base("DefaultConnection")
{
}
public DbSet<User> Users { get; set; }
public DbSet<PrimaryDomain> PrimaryDomains { get; set; }
IQueryable<User> IUserDataSource.Users
{
get { return Users; }
}
IQueryable<PrimaryDomain> IUserDataSource.PrimaryDomains
{
get { return PrimaryDomains; }
}
void IUserDataSource.Save()
{
SaveChanges();
}
}
And this is, for example, how I would pass the PrimaryDomains model to the View:
public class NetworkController : Controller
{
//
// GET: /Network/
private IUserDataSource _db;
public NetworkController(IUserDataSource db)
{
_db = db;
}
public ActionResult ListDomains()
{
var allDomains = _db.PrimaryDomains;
return View(allDomains);
}
}
But instead of pulling the entire PrimaryDomains list from the data source, I would like to add a way to reference the currently logged in user id to make the application only show the domains for that specific user, not all domains, and when adding a new domain via the form to reference the User Id and add it into the table as well.
My original question may have caused some confusion as to what I'm trying to achieve; It's my fault for posing the wrong way of going about what I'm trying to do. After much research and learning, I've found that exactly what I'm looking for is a multi-tenant data architecture approach.
This is probably what you are looking for. If I understood you correctly you want to use WebSecurity to login or register users but you want to use entity framework to store some user-specific data. Code below connects WebSecurity tables with your database CodeFirst created using EntityFramework.
You create class below (from tutorial).
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
{
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Ensure ASP.NET Simple Membership is initialized only once per app start
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
}
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
try
{
if(!WebSecurity.Initialized)
WebSecurity.InitializeDatabaseConnection("ConnectionString", "DbUsers", "UserId", "Email", autoCreateTables: true);
}
catch (Exception ex)
{
throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
}
}
}
}
It creates necessary tables for registering and logging your users. The magic is in second, third and fourth parameter. It is respectively table, userId column and userName column from YOUR database that you can create by EntityFramework. WebSecurity uses that table along with other self-generated tables to manage your users and let them register, login and so on.
Then in your code first you simply create table
public class DbUser
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[MaxLength(40)]
public string Email { get; set; }
[MinLength(3)]
[MaxLength(30)]
[Required]
public string FirstName { get; set; }
[MinLength(3)]
[MaxLength(50)]
[Required]
public string LastName { get; set; }
}
Then you can simply query data from controller. In example below I use UserId stored by WebSecurity membership to retrieve account info from database.
public ActionResult AccountInfo()
{
if (FormsAuthentication.CookiesSupported == true && Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
var userId = WebSecurity.CurrentUserId;
var userInfo = context.Users.FirstOrDefault(x => x.UserId == userId);
userInfo.Password = "";
return View(userInfo);
}
else
{
ModelState.AddModelError("", "Wystąpił bląd autoryzacji, zaloguj się jeszcze raz.");
return RedirectToAction("Login", "Account");
}
}
EDIT:
Regarding your edited question as I understand besides the fact that you need to integrate WebSecurity with EF as above (I also forgot to mention that after creating InitializeSimpleMmebershipAttribute class as above you need to decorate your controller with that attribute) you also have problems with implementing generic repository. If that line is a problem:
var allDomains = _db.PrimaryDomains;
Then i suggest to read this article about implementing generic repository:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
If you want thing realy simple all you need is just add to your interface method
GetDomainByUserId(int userId)
and just implement that interface like that:
public class UserDb : DbContext, IUserDataSource
{
public UserDb()
: base("DefaultConnection")
{
}
public DbSet<User> Users { get; set; }
public DbSet<PrimaryDomain> PrimaryDomains { get; set; }
IQueryable<User> IUserDataSource.Users
{
get { return Users; }
}
IQueryable<PrimaryDomain> IUserDataSource.PrimaryDomains
{
get { return PrimaryDomains; }
}
IQueryable<PrimaryDomain> GetDomainByUserId(int userId)
{
return PrimaryDomains.Where(x => x.Id == userId).ToQueryable();
}
void IUserDataSource.Save()
{
SaveChanges();
}
}
But this is very bad approach and I strongly recommend reading that article.

Resources