ViewModelBase.IsInDesignModeStatic Property - mvvm-light

I am sure this is a MVVM Light newbie error but I need to ask. I am creating an WPF4 application using the MVVM Light framework and Ninject for DI. In the ViewModelLocator contructor I pass in the ViewModelBase.IsInDesignModeStatic value so I know to create DI with DesignTime data or RunTime data.
I thought that when you opened the MainWindow.xml in the designer ( VS2010 or Blend ) that the property would be True and the constructor would execute and break in debug if I had a breakpoint set. The application runs fine and debugs when ran correctly but I never get designtime data because the property is always false. Also does not seem that the constructor is executing when opened in designer. I have watched Laurent's videos multiple times and I know this does work. Can someone please tell me what they think I must be doing wrong.
Orgbrat

I'm late, but try this when troubleshooting this kind of problem.
You'll need a simple Property to test: Create a "Foo" property (string) in the ViewModel and bind it to the XAML (use a TextBlock for example).
In the ViewModel
In the "Get", return an hard coded string (ex: "Step 1". This will validate the "bindings" are valid.
Remove the "Get" hard code, and in the constructor, put a this.Foo = "Step 2" in the first line, this will validate that the constructor is called
Put a third set where the call is "callbacked", this will check that the GetData is being returned
in the "else" of the if (error != null), put the fourth set, and so on...
Example: Here's my MainViewModel constructor.
public MainViewModel(IDataService dataService)
{
this.Foo = "Step 2";
_dataService = dataService;
_dataService.GetData(
(item, error) =>
{
this.Foo = "Step 3";
if (error != null)
{
// Report error here
return;
}
else
{
this.Foo = "Step 4";
}
});
}
My last bug was that I had put the assignment of the data coming back from the GetData in the "if (error != null){...}" ! So it was never called.
Since then, I rewrite the constructor like this:
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
_dataService.GetData(
(item, error) =>
{
if (error == null)
{
// Normal code here
return;
}
else
{
// Report error here
return;
}
});
}

Related

Async task ASP.net HttpContext.Current.Items is empty - How do handle this?

We are running a very large web application in asp.net MVC .NET 4.0. Recently we had an audit done and the performance team says that there were a lot of null reference exceptions.
So I started investigating it from the dumps and event viewer.
My understanding was as follows:
We are using Asyn Tasks in our controllers. We rely on HttpContext.Current.Items hashtable to store a lot of Application level values.
Task<Articles>.Factory.StartNew(() =>
{
System.Web.HttpContext.Current = ControllerContext.HttpContext.ApplicationInstance.Context;
var service = new ArticlesService(page);
return service.GetArticles();
}).ContinueWith(t => SetResult(t, "articles"));
So we are copying the context object onto the new thread that is spawned from Task factory. This context.Items is used again in the thread wherever necessary.
Say for ex:
public class SomeClass
{
internal static int StreamID
{
get
{
if (HttpContext.Current != null)
{
return (int)HttpContext.Current.Items["StreamID"];
}
else
{
return DEFAULT_STREAM_ID;
}
}
}
This runs fine as long as number of parallel requests are optimal. My questions are as follows:
1. When the load is more and there are too many parallel requests, I notice that HttpContext.Current.Items is empty. I am not able to figure out a reason for this and this causes all the null reference exceptions.
2. How do we make sure it is not null ? Any workaround if present ?
NOTE: I read through in StackOverflow and people have questions like HttpContext.Current is null - but in my case it is not null and its empty. I was reading one more article where the author says that sometimes request object is terminated and it may cause problems since dispose is already called on objects. I am doing a copy of Context object - its just a shallow copy and not a deep copy.
Your problem is that a instance members of the HttpContext are not thread safe:
Any public static (Shared in Visual Basic) members of this type are
thread safe. Any instance members are not guaranteed to be thread
safe.
When accessing it the way you are doing (multiple threads) you need to do your own synchronization.
static object locker = new object();
get
{
lock (locker)
{
if (HttpContext.Current != null)
{
return (int)HttpContext.Current.Items["StreamID"];
}
else
{
return DEFAULT_STREAM_ID;
}
}
}
MSDN: system.web.httpcontext
Maybe I'm misreading this, but I'm getting the impression that you're only trying to prevent the null reference error.
public class SomeClass
{
internal static int StreamID
{
get
{
int returnValue;
if (HttpContext.Current != null)
{
if(HttpContext.Current.Items["StreamID"] != null)
{
returnValue = (int)HttpContext.Current.Items["StreamID"];
}
else
{
returnValue = DEFAULT_STREAM_ID;
}
}
else
{
returnValue = DEFAULT_STREAM_ID;
}
return returnValue;
}
}
}

RelayCommand and WeakReference

I have the following:
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
NotWorkingCommand = new RelayCommand(() =>
dataService.GetData((item, error) =>
{
if (error != null)
{
// Report error here
return;
}
WelcomeTitle = item.Title;
}));
}
Can someone please explain why my RelayCommand would stop firing after a while? I suspect it has to do with WeakReference used in the RelayCommand but I have no experience with WeakReference. If I used _dataService.GetData instead, it will work.
In your lambda expression, the dataService.GetData instruction won't work, because the scope of the variable dataService is only limited to the constructor.
Instead you should copy this reference to a backing field and call this instance instead.
If think you were near the solution when you say it works by using _dataService.GetData.
private readonly IDataService _dataService;
public RelayCommand NotWorkingCommand { get; private set; }
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
NotWorkingCommand = new RelayCommand(() =>
_dataService.GetData((item, error) =>
{
if (error != null)
{
// Report error here
return;
}
WelcomeTitle = item.Title;
}));
}
It seems that the delegate is correctly created because the reference exists when the relay command is created (in the scope of the ctor), but it can't be called at runtime because it cannot be evaluated correctly.
marckm is not wrong here and the suggestion to use the class-level variable will work. But I would just like to clarify that the complete answer to this question should include a bit of info on "variable captures" in lambdas.
Before MVVMLight started to use weak references, the method-level variable dataService would by captured in the lambda expression. Normally, this variable would go out of scope once the method completes. Due to variable capture in the lambda, this would not happen here, which is why the body of the lambda would (always) work later on.
After MVVMLight moved to weak references, the code will initially work, but without the class-level variable (and assignment), the method-level variable will eventually be garbage collected, and the RelayCommand will then stop to work. Which is exactly what you saw here (six years ago - I know - but this question remains valid today).

Entity Framework telling me an object is attached when it isn't - why?

I have an object I want to update in the database. I'm new to EF but have done a fair bit of reading. Clearly my approach is wrong, but I don't understand why. FYI the Context referenced throughout is an ObjectContext which is newly instantiated as this code begins and is disposed immediately after. Here is my Update method - the View is the object I want to update in the database and it has 4 ICollection properties whose changes I also wish to save to the database:
public void Update(View view)
{
var original = Read(view.Username, view.ViewId);
original.ViewName = view.ViewName;
ProcessChanges<CostCentre, short>(Context.CostCentres, original.CostCentres, view.CostCentres, "iFinanceEntities.CostCentres", "CostCentreId");
ProcessChanges<LedgerGroup, byte>(Context.LedgerGroups, original.LedgerGroups, view.LedgerGroups, "iFinanceEntities.LedgerGroups", "LedgerGroupId");
ProcessChanges<Division, byte>(Context.Divisions, original.Divisions, view.Divisions, "iFinanceEntities.Divisions", "DivisionId");
ProcessChanges<AnalysisCode, short>(Context.AnalysisCodes, original.AnalysisCodes, view.AnalysisCodes, "iFinanceEntities.AnalysisCodes", "AnalysisCodeId");
int test = Context.SaveChanges();
}
First I get the original from the database because I want to compare its collections with the new set of collections. This should ensure the correct sub-objects are added and removed. I compare each collection in turn using this ProcessChanges method:
private void ProcessChanges<TEntity, TKey>(ObjectSet<TEntity> contextObjects, ICollection<TEntity> originalCollection, ICollection<TEntity> changedCollection, string entitySetName, string pkColumnName)
where TEntity : class, ILookupEntity<TKey>
{
List<TKey> toAdd = changedCollection
.Select(c => c.LookupKey)
.Except(originalCollection.Select(o => o.LookupKey))
.ToList();
List<TKey> toRemove = originalCollection
.Select(o => o.LookupKey)
.Except(changedCollection.Select(c => c.LookupKey))
.ToList();
toAdd.ForEach(a =>
{
var o = changedCollection.Single(c => c.LookupKey.Equals(a));
AttachToOrGet<TEntity, TKey>(entitySetName, pkColumnName, ref o);
originalCollection.Add(o);
});
toRemove.ForEach(r =>
{
var o = originalCollection.Single(c => c.LookupKey.Equals(r));
originalCollection.Remove(o);
});
}
This compares the new collection to the old one and works out which objects to add and which to remove. Note that the collections all contain objects which implement ILookupEntity.
My problems occur on the line where I call AttachToOrGet. This method I got from elsewhere on stackoverflow. I'm using this because I was often getting a message saying that "An object with the same key already exists in the ObjectStateManager" when attaching a new subobject. Hopefully you'll understand my confusion around this when I post the code of this method below:
public void AttachToOrGet<TEntity, TKey>(string entitySetName, string pkColumnName, ref TEntity entity)
where TEntity : class, ILookupEntity<TKey>
{
ObjectStateEntry entry;
// Track whether we need to perform an attach
bool attach = false;
if (Context.ObjectStateManager.TryGetObjectStateEntry(new EntityKey(entitySetName, pkColumnName, entity.LookupKey), out entry))
//if (Context.ObjectStateManager.TryGetObjectStateEntry(Context.CreateEntityKey(entitySetName, entity), out entry))
{
// Re-attach if necessary
attach = entry.State == EntityState.Detached;
// Get the discovered entity to the ref
entity = (TEntity)entry.Entity;
}
else
{
// Attach for the first time
attach = true;
}
if (attach)
Context.AttachTo(entitySetName, entity);
}
Basically this is saying if the entity is not already attached then attach it. But my code is returning false on the Context.ObjectStateManager.TryGetObjectStateEntry line, but throwing an exception on the final line with the message "An object with the same key already exists in the ObjectStateManager". To me this is paradoxical.
As far as I'm concerned I'm trying to achieve something very simple. Something it would take 20 minutes to write a stored procedure for. A simple database update. Frankly I don't care what is attached and what isn't because I don't wish to track changes or create proxies or lazy load or do anything else EF offers me. I just want to take a very simple object and update the database using a minimal number of trips between servers. How is this so complicated? Please someone help me - I've spent a whole day on this!
Update
Here's my ILookupEntity class:
public interface ILookupEntity<TKey>
{
TKey LookupKey { get; }
string DisplayText { get; }
}
Here's how it is implemented in CostCentre:
public partial class CostCentre : IFinancialCode, ILookupEntity<short>
{
#region IFinancialCode Members
public short ID { get { return CostCentreId; } }
public string DisplayText { get { return string.Format("{0} - {1}", Code, Description); } }
#endregion
#region ILookupEntity Members
public short LookupKey
{
get { return ID; }
}
#endregion ILookupEntity Members
}
Well, I've worked through this and found a solution, but I can't say I understand it. The crucial ingredient came when I was performing a check after the comment by #Slauma. I wanted to check I was using the correct entity set name etc so I included the following lines near the top of my AttachToOrGet method:
var key = new EntityKey(entitySetName, pkColumnName, entity.LookupKey);
object temp;
if (!Context.TryGetObjectByKey(key, out temp))
throw new Exception(string.Format("No entity was found in {0} with key {1}", entitySetName, entity.LookupKey));
Bizarrely this alone resolved the problem. For some reason, once I'd called the TryGetObjectByKey then the ObjectStateManager.TryGetObjectStateEntry call actually started locating the attached entity. Miraculous. I'd love it if anyone can explain this.
By the way, I also needed to include the following code, but that's just because in my case the modelled entities are located in a separate assembly from the context itself.
Assembly assembly = typeof(CostCentre).Assembly;
Context.MetadataWorkspace.LoadFromAssembly(assembly);

SEAM: Component "disinjected" "too soon" in interceptor?

Let's say I have the following interceptor in a SEAM app:
public class MyInterceptor {
#In
private Monitor myMonitor;
#AroundInvoke
public Object aroundInvoke(InvocationContext ctx) throws Exception {
try {
myMonitor.a();
return ctx.proceed();
}
finally {
myMonitor.b();
}
}
}
myMonitor.a() works (so Monitor is correctly injected), myMonitor.b() fails because Monitor is already null. Seam Doc says: "Injected values are disinjected (i.e., set to null) immediately after method completion and outjection."
Is that what is happening? Can I do something to tell SEAM to "not yet" "disinject" the component? I can of course also do something like XContext.get(..), but I'm wondering whether this is a bug or a mistake from my side. thanks!
Try this one instead
Object response = null;
try {
myMonitor.a();
response = ctx.proceed();
} finally {
myMonitor.b();
}
return response;
regards,
Avoid using injection.
Try working around this problem. I see you have some sort of monitoring going on. Look at this interceptor that captures the amount of time a method is executed in Seam components. Try modifying your code to match that.
It works great!
Here is the link
Seam is working as advertised.
You could just ignore the disinjection:
public class MyInterceptor {
private Monitor myMonitor;
#In
private void setMonitor(Monitor aMonitor) {
if (aMonitor != null) {
myMonitor = aMonitor;
}
}
#AroundInvoke
public Object aroundInvoke(InvocationContext ctx) throws Exception {
try {
myMonitor.a();
return ctx.proceed();
}
finally {
myMonitor.b();
myMonitor = null; //perform disinjection yourself
}
}
}
The caveat here is that Seam is disinjecting the reference for a reason. Seam wants to control the lifecycle and identity of "myMonitor" and by keeping a reference to it, you are not abiding by your contract with Seam. This could lead to unexpected behavior.
For instance, if myMonitor were for some reason in the Stateless scope, Seam might destroy it before ctx.proceed() returns, leaving you with a reference to a broken proxy. Best advice is to know the scope and lifecycle of what you are retaining since you are "living on the edge."

LINQ to SQL partial class OnValidate Changeaction.Delete

I have a LINQ partial class:
public partial class resp
{
public IEnumerable<RuleViolation> GetRuleViolations()
{
if (String.IsNullOrEmpty(respName))
yield return new RuleViolation("Responsibility name required", "respName");
yield break;
}
public bool IsValid
{
// Quick method for checking to see whether an object contains any RuleViolations
get { return (GetRuleViolations().Count() == 0); }
}
partial void OnValidate(ChangeAction action)
{
// Hook to LINQ to be notified before db is actually persisted .. and check to make sure resp is not used by respApprover or approvals
if (action == ChangeAction.Delete && ((respApprovers.Count() != 0 || approvals.Count() != 0)))
throw new ApplicationException("You cannot delete a responsibility that is in use");
if (!IsValid)
throw new ApplicationException("Rule violations prevent saving");
}
}
In my code I would like to be able to check whether a responsibility (dbo.resp) exists before it is deleted.
I am accomplishing this check with a hook to OnValidate as above ... if (action == ChangeAction.Delete) ... and returning an application exception if it fails.
Also, during normal validation, I would like to check to make sure rule violations aren't made (resp.respName in this case...)
So, normally I can just do a try { } catch { var errors = resps.GetRuleViolations() } and check whether I have validation errors. Of course, that doesn't know what action is being taken (Changeaction.Delete)
I guess my main question is, how can I have OnValidate return a reason rather than crash my whole app when the Changeaction is delete. Normally I would catch GetRuleViolations but if I put the 'if statement' in the GetRuleViolations ... it will always be true even during checks to see if the data was correct (in other words, respApprovers.Count() will matter even for checks on new insertions which I don't want to. I only want those count checks to be made on deletion)
Or possibly more simply stated: I want GetRuleViolations to tell me when someone attempts to delete resp that has respApprovers.Count() > 0 or approvals.Count() > 0 but only when the OnValidate Changeaction is delete.
Change GetRuleViolations to accept the ChangeAction parameter and add a parameterless version that calls it with ChangeAction.None (or Update or Insert, as appropriate). Then move your check in there as you want.
public IEnumerable<RuleViolation> GetRuleViolations( ChangeAction action )
{
if (action == ChangeAction.Delete) {
...
}
else {
...
}
}
public IEnumerable<RuleViolation> GetRuleViolations()
{
return GetRuleViolations( ChangeAction.None );
}

Resources