c# MVC 5 User Store custom findby - c#

the default provided FindByIdAsync, FindById etc work as expected.
How would I go about implementing a FindBySomeOtherField?
at a minimum i'd like to be able to UserManager.FindBy any field off the main AspNetUsers table. Such as UserManager.FindByPhoneNumber
Ideally, i'd be able to UserManager.FindByCustomField
I do NOT want to implement a completely new user store.
I guess worst case scenario I could go find and copy the entire user store for MVC 5 as is and add it to my project and then implement it, however, i'd rather just add a class that includes the function and be done since I rather like the user store as is and just want to extend it's functionality.

Not sure if I'm understanding correctly, but the following should work?
IEnumerable<[Object]> results = [ObjectCollection].Where(u => u.[Field] == [Value])
OR
[Object] result = [ObjectCollection].SingleOrDefault(u => u.[Field] == [Value])
If you want it for a specific field, you could extract it into a method;
public [Object] FindBy[Field]([FieldType] value)
{
return [ObjectCollection].SingleOrDefault(u => u.[Field] == [Value])
}

Related

How do I update a MongoDB document but exclude a specific field?

I am creating a web API. I need something like this:
When I updating a document at mongodb, I do not want to update a field (createdAt). I know that I can get a old value of that field and manuelly and then put it updated object but it requires one more unnecessarry request to db. I do not want this. My method is here:
public async Task<bool> UpdateAsync(Customer updatedCustomer)
{
var result = await _mongoService.Customers.ReplaceOneAsync(c => c.Id == updatedCustomer.Id, updatedCustomer);
return result.IsModifiedCountAvailable && result.ModifiedCount>0;
}
Is there any way to exclude one property of my Customer class (createdAt) and left it same everytime. BTW please do not recomend that set all properties update one by one by using "Set" method. Thank you.
I'm not sure if there is a way other than to set the properties one by one, but researching the following may be helpful or suggestive of something new.
In Mongodb you can use some decoration to do like [BsonIgnore] but it will ignore it every time
One alternative would be to load the document you wish to modify, followed by calling BsonDocument.Merge with overwriteExistingElements set to true in order to merge your changes.

acumatica c# / Add SOPackageDetailEx

I have this error when I try to add a line of package
Error : Another process has added the "SOPackagedetail" record. Your changes will be lost.
error
My c# code is this :
protected virtual void creationColis()
{
SOShipment ship=Base.CurrentDocument.Select();
SOPackageDetailEx colis = new SOPackageDetailEx();
colis.BoxID="COLIS";
colis.PackageType="M";
colis.ShipmentNbr=ship.ShipmentNbr;
SOShipmentEntry graph = PXGraph.CreateInstance<SOShipmentEntry>();
graph.Packages.Insert(colis); //insertion de l'enregistrement
graph.Packages.Update(colis);
graph.Actions.PressSave();
graph.Clear();
}
Do you know what I must to change please ?
Thanks so much
Xavier
Your question needs more context. For starters, where does your code reside? Given that you reference Base.CurrentDocument.Select, I'm going to assume you are extending SOShipmentEntry to add your code.
In this case, you would just use the Base.Packages view rather than initializing your own instance of SOShipmentEntry where your example goes into trying to use graph.Packages. Regardless, there are 2 parts here that need to be addressed.
Packages is not the primary view of SOShipmentEntry. When you create an instance of a graph, you must tell the graph what record is needed in the primary view. In your example where you create a new instance of a graph, you might do something like this:
graph.Document.Current = graph.Document.Search<SOShipment.shipmentNbr>(myShipmentNbr);
If you are working on a graph extension of SOShipmentEntry, then you probably don't need to create a new instance of the graph. Just make sure graph.Document.Current isn't null before you add your package record - see bullet 2.
Once you have a shipment selected, you can then insert your package information. However, the way you have done it here effectively is trying to add a random package to a null shipment (by the structure of the views) but forcing the record to attach to the right shipment by sheer brute force. The views don't like to work that way.
A better way to add your package once you have a current shipment (Document) is like this:
// Find the current shipment (from the primary view Document)
SOShipment ship = Base.Document.Current();
if(ship?.ShipmentNbr != null) {
// Insert a record into the Packages view of the current shipment and return the record into colis
SOPackageDetailEx colis = Base.Packages.Insert(colis);
// Set the custom values
colis.BoxID="COLIS";
colis.PackageType="M";
// Update the Packages cache with the modified fields
Base.Packages.Update(colis);
// If more fields need to be updated after those changes were applied, instead do this...
colis = Base.Packages.Update(colis);
colis.FieldA = ValueA;
colis.FieldB = ValueB;
Base.Packages.Update(colis);
// If a save is needed, now is the time
Base.Save.Press();
}
Notice that I didn't assign ShipmentNbr. That is because the DAC has that field defined to pull the ShipmentNbr from SOShipment through these 2 attributes.
[PXParent(typeof(FK.Shipment))]
[PXDBDefault(typeof(SOShipment.shipmentNbr))]
This means that when the record is created, Acumatica should lookup the parent SOShipment record via the Key and do a DBDefault on the field to assign it to the SOShipment.ShipmentNbr value (from the parent). Important side note: PXDefault and PXDBDefault are NOT interchangeable. We use PXDefault a lot, but off the top of my head I can't think of a case of PXDBDefault outside of defaulting from a database value like this specific usage.

LanguageExt: How do I do the equivalent of Option<T>.Match with a [Union]?

I want to create a union that will act a bit like Option<T>, but that allows a 3-way state, rather than a 2-way state. The reason for this is to use it when loading data from a database.
If I were doing this with an Option<T>, I would do something like this...
Option<Person> jimOpt = Option<Person>.None;
Person jimOpt = await _appDbContext.People.FirstOrDefault(p => p.Id == 1);
jimOpt.Match(person => {
Console.WriteLine("Jim was found");
},
() => {
Console.WriteLine("No such Jim");
});
However, this doesn't distinguish between when the data is still loading and when the person is not found. This means that while the data is loading, the Option is in the None state, which gives the wrong impression in the UI, as it looks (briefly) as if the data was not found.
My idea is to create a Union like this...
[Union]
public interface Loading<T> {
Loading<T> NotLoaded(); // Initial state, data not loaded yet
Loading<T> Loaded(T value); // Data loaded successfully
Loading<T> NotFound(); // Data access complete, but entity not found
}
...and do something like above, but setting it to be NotLoaded<Person> whilst the data access is going, and then either Loaded<Person> or NotFound<Person> when the data access has completed.
The problem is that the generated Union doesn't seem to have anything to help me here. I thought the idea of the code generation was to take away a lot of this grunt work.
Do I need to implement Match, Map, etc myself, or did I miss something in the code generation?
Thanks.
Match is now generated for Union types. You can also use the c# switch expressions

How to query ASP.NET MVC 5 application for class-level attributes

In my MVC 5 controllers, I often place a class-level custom attribute to manage user access permissions, e.g.
[RoleAuthorize("CreditSlipLog")]
public class CreditLogCreditSumController : Controller
{
I was wondering if it is possible to query the application to list the existing attributes for each controller class in my application (spread across multiple areas).
I know how to write LINQ queries, but I don't know what object to select against. In pseudo-code, I imagine something like this:
var list = (queryable list of areas, classes and their attributes)
.Where(controller has "RoleAuthorize" custom filter)
.Select(m=> new {
Area = m.Area,
Controller = m.ControllerName,
RoleAuthorizeValue = m.ControllerAttributeValue
}).ToList();
where, "RoleAuthorizeValue" is parameter value of [RoleAuthorize]
So an example result might look like this:
Area | Controller | RoleAuthorizeValue
------------------------------------------------------------
Credit | CreditLogCreditSumController | CreditSlipLog
Is there a single object I can query against, or is the query going to be very messy? Or is it something that is even possible? While I can do this manually, it is a very large application and still subject to change, making a manual document quickly out of sync with any changes in the application.
You would need to use reflection for that and a query similar to below.
var controllersByAreas = Assembly.GetAssembly(typeof(CreditLogCreditSumController))
.GetTypes()
.Where(type => type.IsClass
&& type.IsSubclassOf(typeof(Controller))
&& type.GetCustomAttributes(typeof(RoleAuthorize), false).Any())
.GroupBy(x => x.Namespace);
In addition to just searching for the attribute you may consider extracting the attribute and check for its properties. Resulting set can be then grouped and printed out.
If Areas of your controllers belong to specific namespaces you may consider grouping by Namespace property of the Type too, see updated code.

Want to add a new property to a class, can I use anonymous functions for this?

I have 2 Lists:
List<User>
List<UserStats>
So I want to add a property Count to User (it doesn't have one now, and I can't change the implementation at this point).
For a web service call, that returns json, I want to modify the User object.
Basically I add the Users to a collection. So I want to add a modified user class (via anonymous functions?) to the collection before I serialize it to json.
So something like:
loop users {
user.Count = userstats[user.ID].Count;
list.Add(user);
}
is this possible? how?
Yes, you can use anonymous types for this:
users.ConvertAll(u => new {
u.NormalProperty, // repeat for properties you want
Count = userstats[user.ID].Count
});
You can probably achieve the same with a LINQ join, selecting out the anonymous type.

Categories