Null field, but not null - c#

So I've got the following lines of code:
else
{
//if not found, call Gateway Add()
user.Id = await C3SDbContext.UserGateway.NextIdAsync(context);
user.CreatedById = modifier.CreatedById;
user.CreatedBy = modifier.CreatedBy;
user.DateCreated = DateTime.Now;
user.UserType = "G";
System.Diagnostics.Debug.WriteLine(user.UserType);
user.Status = UserStatus.NEW;
System.Diagnostics.Debug.WriteLine(user.UserType);
user.Uic = await C3SDbContext.UicGateway.GetUicByIdAsync(context, user.UicId);
System.Diagnostics.Debug.WriteLine(user.UserType);
user.Role = await C3SDbContext.RoleGateway.GetRoleByIdAsync(context, user.RoleId);
System.Diagnostics.Debug.WriteLine(user.UserType);
if (ModelState.IsValid)
{
userCheck = await C3SDbContext.UserGateway.AddNewGovernmentUserAsync(context, user, modifier);
}
else
{
System.Diagnostics.Debug.WriteLine(user.UserType);
ICollection<ModelState> ListValues = ModelState.Values;
List<object> Errors = new List<object>();
foreach (var item in ModelState.Values)
{
if (item.Errors.Count() > 0)
{
Errors.Add(item.Errors);
}
}
}
}
user is an instance of GovernmentUser.cs, which inherits from User.cs. UserType is a string property of User. When I run this, all the instances of "System.Diagnostic.Debug.WriteLine(user.UserType);" return "G" in the Output window. Heowever, the Errors list returns one item, telling me that UserType is null.
My questions are: what is going on here? How can they both come to different results, when executed at the same type, and how can I get it so that ModelState.IsValid == true?

ModelState checks the data that was posted to you in MVC. I don't know if this is in your controller or not, but if it is, then my guess is that the UserType wouldn't be on the original data that was posted. I don't think you can use that check after setting it server-side. It is a check on the data received from the client. If UserType isn't required on the client side, just remove that rule from the Dto. However, if you are uploading the actual Entity directly here and it is using the Required attribute that EF uses, then I would just save it like normal and let EF handle the valdiation instead of using ModelState.

Related

How to insert or update properties in Active Directory Users and Groups

I am making a windows application that sync the source data to Active Directory.
This application works like this.
Choose Source Data(Department, User)
Mapping user or department attributes from source data
When Application service is run, it create groups and users in Active Directory
And also it sets the attributes to users and groups.
When I try to set group or user attributes(properties), it throws exception message like this.
in DirectoryEntry.CommitChanges(); block
The directory
service cannot perform the requested operation on the RDN attribute of an object.
I tried to solve it, but it's really hard to me because I`m not good at Active directory...
Code is below, Please share your knowledge.
//ppk: department key column, pk:user key column, row : Source DataTable's row
void CreateADUser(string ppk,string pk,DataRow row)
{
//password
string pass = GetPass(pk,row,LogSections.AD);
//OU
DirectoryEntry addept = adm.FindOU(ppk);
//principal path
string sOU = adm.GetPrincipalPath(addept);
var aduser = adm.CreateNewUser(sOU, pk, pass, pk, null, null, adm.sDomain);
SetAdUserProperties(pk, pass, row);
MoveUser(ppk,pk);
}
void SetAdUserProperties(string pk,string pass,DataRow row)
{
if (row == null) return;
//list of mapped column(AD User attributes)
List<ADMapping> MappingPatterns = GetAdMappings(Words.User,false);
//Columns name of Source Data table's row
var colnames = Tool.GetColNames(row);
//get user proterties
var aduser = adm.GetUser(pk);
//directory entry of users
var de=aduser.GetUnderlyingObject() as DirectoryEntry;
//looping mapped column of user attributes
foreach (var ADMap in MappingPatterns)
{
string val = ADMap.Mapping;
//mapped columns value
val=Util.ReplaceColPattern(val, row);
SetProperty(de, ADMap.CN, val);
}
if (!string.IsNullOrWhiteSpace(pass))
{
var UserPkColumn = AppConfigHelper.GetAppString(Words.SourceUserPKColumn);
UserPkColumn = Util.GetActualColName(UserPkColumn);
aduser.SetPassword(pass);
QueryHelper.Update(QueryHelper.ConnectionString, Words.ShadowUserTable
,new SqlParameter[] { new SqlParameter("#passwd", pass) }
, new SqlParameter("#"+UserPkColumn,pk));
}
aduser.Save();
}
public void SetProperty(DirectoryEntry oDE, string sPropertyName, object sPropertyValue)
{
if (sPropertyValue != null && !string.IsNullOrWhiteSpace(sPropertyValue.ToString()))
{
if (oDE.Properties.Contains(sPropertyName))
{
oDE.Properties[sPropertyName].Value = sPropertyValue;
}
else
{
oDE.Properties[sPropertyName].Add(sPropertyValue);
}
try
{
oDE.CommitChanges(); //exception here.
oDE.Close();
}
catch (Exception)
{
}
}
}
I also asked this question to other forums, and finally got it.
Before DirectoryEntry.CommitChanges(); set UserPropertyCache property to true
and call the RefreshCache method.
It's hard to see what's the cause of the issue here as we're not seeing what attributes you are trying to set.
That said, you can't just add an attribute if it doesn't exist on your AD object so this part of your code definitely has an issue :
if (oDE.Properties.Contains(sPropertyName))
{
oDE.Properties[sPropertyName].Value = sPropertyValue;
}
else
{
//The following line will never work in this context
oDE.Properties[sPropertyName].Add(sPropertyValue);
}
If I had to make an educated guess, I'd say you're either trying to set an attribute that can't be set, or the User you're adding doesn't have all it's mandatory attributes set.

How to find current user within model in asp.net mvc

I have a table for messages and another table for messageviews. I'm looking to show unread messages to an individual user. With my message table, I've sent up a new field that looks to see if any messageviews exist for the current message. If they do, then my Viewed bool should return true otherwise false(if they haven't viewed the message). Everything works fine, except that I'm unable to find the currently logged in user with User.Identity.GetUser() as I normally would. I've added the correct usings as well. Is there some limitation within a model to restrict this type of call. If so, how can I find the current user within a model?
public bool Viewed
{
get
{
ApplicationDbContext db = new ApplicationDbContext();
//var _userId = User.Identity.GetUserId();
var _userId = Thread.CurrentPrincipal.Identity.GetUserId();
List<MessageView> m_List = db.MessageView.Where(u => u.UserId == _userId && u.MessageId == O_MessageId).ToList();
var count = m_List.Count();
if (count >= 1)
{
return true;
}
else
{
return false;
}
}
}
Resolved: Outside of a controller you can find the current user with this -
var _userId = System.Web.HttpContext.Current.User.Identity.GetUserId();
Outside of a controller you can find the current user with this:
var _userId = System.Web.HttpContext.Current.User.Identity.GetUserId();

MVC Global variables reseting to null when entering another action method

public class MusicController : Controller
{
User currentUser;
public PartialViewResult UploadMusic()
{
return PartialView("_UploadMusic");
}
[HttpPost]
public ActionResult UploadMusic(List<HttpPostedFileBase> files)
{
EntityDBContext db = new EntityDBContext();
List<Song> uploadedSongs = new List<Song>();
foreach (var file in files)
{
if (file != null)
{
string songName = Path.GetFileName(file.FileName);
byte[] songAsBytes = new byte[file.ContentLength];
using (BinaryReader br = new BinaryReader(file.InputStream))
{
songAsBytes = br.ReadBytes(file.ContentLength);
}
//Save new record in database
Song song = new Song
{
SongName = songName,
SongBytes = songAsBytes
};
uploadedSongs.Add(song);
}
}
string userName = User.Identity.Name;
currentUser = db.Users.Where(x => x.Username == userName).First();
currentUser.UserSongs = uploadedSongs;
return ShowSongs(currentUser.UserSongs);
}
public ActionResult ShowSongs(List<Song> UserSongs)
{
return View("ShowSongs", UserSongs);
}
public ActionResult Publish()
{
EntityDBContext db = new EntityDBContext();
foreach (var song in currentUser.UserSongs)
{
if (song != null)
{
db.Songs.Add(song);
db.SaveChanges();
}
}
return View();
}
}
ShowSongs view:
#model List<Vidafo.Models.Song>
#Html.ActionLink("Publish", "Publish")
The Problem
So I declare currentUser at the top of the controller. I then assign a value to that with this line here currentUser.UserSongs = uploadedSongs; This works fine but when the code goes into Publish() currentUser.UserSongs is null.
I need to have access to currentUser.UserSongs in more than one action method after assigning a value but it seems that it resets to null when it enters another action.
Object state isn't maintained across requests, that's not how web applications work. Every time a request is sent to the server, a new instance of the controller object is created. So any instance-level values are new.
In order to persist information across requests you need to persist it somewhere. For something like a user context, session state is a common choice. You'll probably want to wrap it in a common provider interface so as to not couple your controllers to an HTTP context, but at its core storing in session is simple:
HttpContext.Current.Session["someKey"] = someValue;
(You could even re-fetch from the database with each request. It's slightly less performant, but very simple and robust.)
Don't count out the ASP.NET identity system for this, though. ASP.NET is pretty good at abstracting a lot of this for you. You're already using it here:
string userName = User.Identity.Name;
Then you use that value to get the user from the database. You could extend the identity system to store a custom user object which fits your needs. But that's a larger scope effort outside of this question.
For this you can make use of TempData i.e. store value in TempData dictionary. One problem here is MVC doesn't sore value of variable during postback i.e. during different action of same controller or calling another controller for this you can use temporary varialble TempData as suggested.

Trying to eliminate redundant code execution for validation and entity

I'm looking to see if there is a way to eliminate one of the two calls that gets made to my method to google maps to calculate long/lat coordinates.
Here is my method.
public static GeocoderCoordinates GetCoordinates(string region)
{
WebRequest request = WebRequest.Create("http://maps.googleapis.com/maps/api/geocode/xml?sensor=false&address=" + HttpUtility.UrlEncode(region));
using (WebResponse response = request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
XDocument document = XDocument.Load(new StreamReader(stream));
XElement longitudeElement = document.Descendants("lng").FirstOrDefault();
XElement latitudeElement = document.Descendants("lat").FirstOrDefault();
if (longitudeElement != null && latitudeElement != null)
{
return new GeocoderCoordinates
{
Longitude = Double.Parse(longitudeElement.Value, CultureInfo.InvariantCulture),
Latitude = Double.Parse(latitudeElement.Value, CultureInfo.InvariantCulture)
};
}
}
}
return null;
}
The first time I call this method it's for validation.
internal class ValidateLocationAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
var location = value as string;
GeocoderCoordinates coordinates = Geocoding.GetCoordinates(location);
if (coordinates == null)
return false;
return true;
}
}
and if there is no location that gets found it returns null - validation fails.
The second time it gets called is in the controller to set longitude/latitude coordinates within my entity.
[HttpPost]
public ActionResult Edit(EditStudentViewModel viewModel)
{
if (ModelState.IsValid)
{
Student student = studentRepository.Find(User.Identity.GetUserId());
if (student == null)
{
var newStudent = new Student
{
AspNetUserRefId = viewModel.AspNetUserRefId,
CatchPhrase = viewModel.CatchPhrase,
StartedPracticing = Convert.ToInt16(viewModel.SelectedYearId),
LocationPoints = Geocoding.GetDbGeography(viewModel.Location),
Location = viewModel.Location,
SO I'm running through this method twice just to insert/update a student. It seems a little redundant.
Isn't there a way to trigger/set validation state while the code in the controller is running, so I don't have to call this method twice (once for validation and once to set the actual values) when the user submits the form?
I thought about caching but don't think it's a good idea, unless someone can point out something.
If you think applying validation upfront using an attribute on the text box serve value to the user (early feedback), keep things as it is. Two calls is not too bad at all considering the value and cleanliness of the solution.
Second option is you can remove the attribute, and perform the validation in the controller action. If validation fails, display same form with all the same data but error message for the text box value (location). User will need to choose another location and then submit.
It is a trade off.
Important Tip: You can optimize your solution by storing region names in your DB and going to google API only if the region name does not present in your DB.

Parse.com - if key exists, update

Currently, I'm sending some data to Parse.com. All works well, however, I would like to add a row if it's a new user or update the current table if it's an old user.
So what I need to do is check if the current Facebook ID (the key I'm using) shows up anywhere in the fbid column, then update it if case may be.
How can I check if the key exists in the column?
Also, I'm using C#/Unity.
static void sendToParse()
{
ParseObject currentUser = new ParseObject("Game");
currentUser["name"] = fbname;
currentUser["email"] = fbemail;
currentUser["fbid"] = FB.UserId;
Task saveTask = currentUser.SaveAsync();
Debug.LogError("Sent to Parse");
}
Okay, I figured it out.
First, I check which if there is any Facebook ID in the table that matches the current ID, then get the number of matches.
public static void getObjectID()
{
var query = ParseObject.GetQuery("IdealStunts")
.WhereEqualTo("fbid", FB.UserId);
query.FirstAsync().ContinueWith(t =>
{
ParseObject obj = t.Result;
objectID = obj.ObjectId;
Debug.LogError(objectID);
});
}
If there is any key matching the current Facebook ID, don't do anything. If there aren't, just add a new user.
public static void sendToParse()
{
if (count != 0)
{
Debug.LogError("Already exists");
}
else
{
ParseObject currentUser = new ParseObject("IdealStunts");
currentUser["name"] = fbname;
currentUser["email"] = fbemail;
currentUser["fbid"] = FB.UserId;
Task saveTask = currentUser.SaveAsync();
Debug.LogError("New User");
}
}
You will have to do a StartCoroutine for sendToParse, so getObjectID has time to look through the table.
It may be a crappy implementation, but it works.
What you need to do is create a query for the fbid. If the query returns an object, you update it. If not, you create a new.
I'm not proficient with C#, but here is an example in Objective-C:
PFQuery *query = [PFQuery queryWithClassName:#"Yourclass]; // Name of your class in Parse
query.cachePolicy = kPFCachePolicyNetworkOnly;
[query whereKey:#"fbid" equalTo:theFBid]; // Variable containing the fb id
NSArray *users = [query findObjects];
self.currentFacebookUser = [users lastObject]; // Array should contain only 1 object
if (self.currentFacebookUser) { // Might have to test for NULL, but probably not
// Update the object and save it
} else {
// Create a new object
}

Categories

Resources