I am trying to use a business object that I am passing to the report.rdlc. The properties in my object are not directly exposed. The properties I require are embedded within another object inside the top level object. As this is a WCF project I can't control what goes on at the server end. I am just able to request these objects or Insert/Update/Delete their info from the database. It is done in this way as the back end can use multiple flavors of database.
Here is what I can see after adding my business object as a DataSource:
-BusinessObject
-CustomerInfo
-ClientName
-ColumnName
-DisplayName
-FieldName
-IsNull
-KeyColumn
-SenondKeyColumn
-StringValue
-ClientID
-ColumnName
-DisplayName
-FieldName
-IntValue
-IsNull
-KeyColumn
-SenondKeyColumn
+ClientAddress
+Instrument
+Telephone
etc etc
I need to be able to display, for example, the ClientName.StringValue field.
If I drag the field I want onto the report I get:
=First(Fields!StringValue.Value)
This doesn't display anything when the report is run, I assume because it can't qualify what StringValue it is talking about and there could be many.
If I try dragging the ClientName object I get:
=First(Fields!ContactName.Value)
However this gives:
#ERROR
When the report is run.
I would have thought you could use:
=First(Fields!ClientName.StringValue.Value)
but this won't even let me build.
The problem was that the info wasn't at the root level. I worked it out though.
=First(Fields!ClientName.Value.StringValue, "BusinessObject_CustomerInfo")
I've got a pretty good grip of the ReportViewer component now cheers.
If you set the data source to the CustomerInfo instance (or list) returned from the service it should work. The ReportViewer control can be a little complicated when you start dealing with object hierarchies, but you don't have to do anything crazy or special if all the information is at the root level.
Related
I have tried finding an answer to this question practically everywhere I could imagine, including here on StackOverflow. Unfortunately to no avail. So here it is.
I'm working on an Outlook Add-in (with Outlook 2021), and have developed some code that creates some ItemProperties specifically for use with that add-in. Now, when those properties are created, I can see them when I go to View->Settings->Advanced View Settings->Columns, as illustrated in the screenshot.
Screenshot of User-defined fields in Outlook
In some cases, though, I want to completely delete the properties. And as I know how to do that manually, as pointed out in the figure, I can't find out how to do that programmatically via C#. I have gone that far as to remove the properties from each mail containing that kind of property, like this:
IEnumerable<MailItem> listOfAssignedEmails = itemsToProcess.Where(
t => t.ItemProperties[MailExpiration.ExpirationDatePropertyName] != null);
foreach (MailItem email in listOfAssignedEmails)
{
// Note: The Delete() operation is deprecated. A more up-to-date method must be found.
email.ItemProperties[MailExpiration.ExpirationDatePropertyName].Delete();
email.Save();
}
... and yes, I know that the Delete() operation is deprecated; however, I couldn't find another method for removing the ItemProperty from the email (any suggestions are welcome).
Basically, the deletion of this Property is only going to be done very rarely (t. ex. if the user chooses to uninstall the Add-in. However, if there's any way to remove that property automatically, I would be happy to know.
Any suggestions will be greatly appreciated.
It is really a bad idea to remove a custom property from all emails that already have it: there is really no point since the user will never see them, but you will have to retouch (and thus change the last modified date) of a large number of emails.
Also note that named properties in MAPI are a finite resource - you can have at most 64k of them in a mailbox. Once a particular property mapping is used, you can never unmap it, even if there are no items that use that property.
Thirdly, doing anything Outlook related from an installer (rather than a VSTO addin) is a really bad idea - Windows installer runs in a service.
If you want to make sure the user no longer sees your custom fields as available properties in a view, you need to deal with the folder fields - they ar stored in a blob in a hidden (associated) message in that folder. OOM does not expose folder fields at all (if you don't count the AddToFolderFields parameter when calling UserProperties.Add). If using Redemption is an option (I am its author), it exposed RDOFolderFields object (accessible from RDOFolder2.FolderFields property) that allows to add or delete folder fields.
The list of properties shown on the screenshot belongs to the Folder.UserDefinedProperties property which returns a UserDefinedProperties object that represents the user-defined custom properties for the Folder object.
Use the ItemProperties.Remove method removes an object from the collection (from an item).
Use the ItemProperties property to return the ItemProperties collection. Use ItemProperties.Item(index), where index is the name of the object or the numeric position of the item within the collection, to return a single ItemProperty object.
I've been trying to use the TSqlModel method DeleteObjects to programmatically remove certain users from a Database project. The problem is that when I call the method, the user remains in the model. I wonder if I am calling the method correctly. Here's something close to what I am doing:
modelFromDacpac.DeleteObjects(#"DOMAIN\user");
When I run the following code to see if it's really gone, the user is still there!
var tst_delete= modelFromDacpac.GetObjects(User.TypeClass, new ObjectIdentifier(#"DOMAIN\user"), DacQueryScopes.Default).FirstOrDefault();
tst_delete is non-null and has a name that matches "DOMAIN\user".
Any idea what I'm doing wrong?
Prior to the DeleteObject method call, I insert the following line - where the sqlobj object is a TSqlObject referring to the user I am trying to delete
//For some reason, the logins aren't scripted objects within the DACPAC, and so cannot be deleted using the DeleteObjects method - or maybe they simply cannot be found.
modelFromDacpac.ConvertToScriptedObject(sqlobj, "DOMAIN_user.sql");
Then I call the DeleteObject method as follows:
modelFromDacpac.DeleteObjects("DOMAIN_user.sql");
I'm not sure why this works, but it does. My guess is that the DeleteObject method is pretty picky about how and where it expects to find objects. Or, maybe some objects, like users, are stored in some non-standard fashion which prevents DeleteObjects from finding them. Whatever the reason, but explicitly converting the user to a scripted object with a given name, and passing that given name to the DeleteObjects method, it works.
I am a little concerned that I do not know why it works. The other concern is that it doesn't show up in the official documentation of the TSqlModel object:
https://msdn.microsoft.com/en-us/library/microsoft.sqlserver.dac.model.tsqlmodel_methods(v=sql.120).aspx
But it does work. At least, so far.
DeleteObject caught me out the same way :) - it only deletes scripts added using AddOrUpdate when you also pass in a script name and Delete uses the same script name.
What you need to do is create a new model and add in everything except the things you want to delete.
Why do you want to delete a login? If you don't want it to be deployed you can use a deployment contributor like my one here to exclude the login at deployment time:
https://the.agilesql.club/Blogs/Ed-Elliott/HOWTO-Filter-Dacpac-Deployments
Ed
I'm trying to do something my teacher says can't be done; I would like to prove him wrong.
In the CreateChildControls method of my SharePoint 2010 webpart, I am referencing a User Control file called "ChartUserControl.ascx" in my project that contains the ASP.NET code for a WebChartControl object configured just the way I want it. WebChartControl has an ID of "OrderQtyChart".
What I want to do is take the code from that UserControl and use it create a new WebChartControl, called "chart", with matching configuration. I'm trying to do this because there are callbacks etc. that need to be performed on the chart after it's created to actually populate it with chart-stuff.
So, my code:
WebChartControl chart;
protected override void CreateChildControls()
{
ChartUserControl userControl = new ChartUserControl();
// referencing file ChartUserControl.ascx as an object
chart = userControl.FindControl("OrderQtyChart") as WebChartControl;
// or
chart = (WebChartControl)userControl.FindControl("OrderQtyChart");
// Trying to tell the code to create 'chart' using the code defined in object
"OrderQtyChart" located in ChartUserControl.ascx
}
Or something like that. In either instance above, 'chart' will return null.
I'm trying to use the front end code of OrderQtyChart as a template for 'chart'; they're both the same type of object and I don't get any errors until I try to create 'chart' on my page, at which point I'm told it's null.
Is there a way to do this? It would save me a ton of time not to have to configure 'chart' completely at creation time. Even if I have to reference my front-end code for OrderQtyChart a different way.
Thanks.
[Edited 7/9 for clarity]
What you are trying to do seems very well possible and I assume your teacher did not understand your question correctly. Here are a few tips on how this is done:
Object A could be one of these:
A visual control such as label or textbox. In this case your will have to traverse the visual controls from parent to child by doing direct parent.FindControl("ObjectA");
It is an instance of a class. This might be a MyClass or a new textbox that is created by code. In this case you'll have to create a public property that has a getter which returns ObjectA. although you can use FindControl in case ObjectA is a UI component that is created and added dynamically at run-time. Otherwise, you'll have to stick with property.
FindControl will not traverse the parent to child hierarchy, so you'll have to do a recursive method in order to successfully find the ObjectA or if you have access to its direct parent, call FindControl on that. More info here: http://geekswithblogs.net/QuandaryPhase/archive/2009/05/06/asp.net-recursive-findcontrol-amp-extension-methods.aspx
Page life cycle plays an important role here, so make sure that you keep it in mind or you'll end up with a null reference that is not really caused by FindControl
Gah, never mind. I realized I can just call the user control directly and I'm seriously overcomplicating this.
That's a whole new question, so I'll just start a different thread.
Hello fellow developers.
First of all I apologize beforehand for the wall of text that follows, but after a day going crazy on this, I need to call for help.
I've stumbled across a problem I cannot seem to solve. I'll try to describe the scenario in the best possible way.
Task at hand: in an existing Asp.Net Mvc application, create a lookup table for an integer field, and use the textual value from the lookup in the editing view. When saving, we must first check if the lookup already has a corresponding text value for the same Root ID. If there is, use that. Otherwise, create it and then use it.
The structure:
The data model is a graph of objects where we have the root object, a collection of level A child objects, and every level A child object has a collection of level B child objects, so something like this:
Root (with fields)
Level A child (with fields) x n
Level B child (with fields) x n
The field we have to handle is on the LevelB objects.
There is a single Mvc view that handles the whole data. For collection objects, all fields are named like levelA1levelB1MyField, levelA1levelB2MyField, etc so every single field has unique name during the post. When the post happens, all values are read through a formCollection parameter which has average 120/130 keys. The keys are isolated by splitting them and looping on the numerical part of the names, values are read and parsed to the expected types and assigned to the object graph.
The datalayer part backing the object graph is all stored procedures, and all the mapping (both object to sproc and sproc to object) is hand written. There's a single stored procedure for the read part, which gets multiple datasets, and the method calling it reads the datasets and creates the object graph.
For the saving, there are multiple sprocs, mainly a "CreateRoot" and "UpdateRoot". When the code has to perform such tasks, the following happens:
For create scenario, "CreateRoot" is called, then the sprocs "CreateLevelA" and "CreateLevelB" are called in loop for each element in the graph;
For update scenario, "UpdateRoot" is called, which internally deletes all "LevelA" and "LevelB" items, then the code recreates them calling the aforementioned sprocs in loop.
Last useful piece of information is that the "business objects graph" is used directly as a viewmodel in the view, instead of being mapped to a plain "html friendly" viewmodel. This is maybe what is causing me the most trouble.
So now the textbox on the view handles an "integer" field. That field must now accept a string. The field on LevelB must remain an integer, only with a lookup table (with FK of course) and the text field from the lookup must be used.
The approaches I tried with no success:
My first thought was to change the datatype on the property MyField from integer to string on the object, then change the sprocs accordingly and handle the join at sproc level: I'd have a consistent object for my view, and the read/write sprocs could translate from string to integer and viceversa, but I can't do that because the join keys to retrieve the integer when writing are part of the Root item (as I stated in the first lines of this wall of text), which I don't know in the CreateLevelB sproc, and changing the whole chain of calls to pass those parameters would have a huge impact on the rest of the application, so no good.
My next try was to keep things "as they are" and call some "translation methods": when reading, pass the integer to the view, and there call the translation method to display the text value. When saving, use the posted text to retrieve the integer. The save part would work, I'd have all the parameters I need, but for the read part, I'd have to instantiate the "data access layer" and call its method at View level, and there's no need to explain why that is a very bad choice, so I ruled this out too.
Now I'm out of options (or ideas anyway). Any suggestion to solve this is very welcome, and also if something is not clear enough just point it out and I will edit my post with more accurate information.
Thanks.
This is not a real answer but you could rip out all sprocs and use the updating facilities of an OR mapper. This will resolve all the layering issues. You just update data how you see fit and submit at the end.
I guess this would also make the questions around "should I use an int or a string" go away.
Edit: After reading your comment I thought of the following: Do not implement alternative 1. You rather want to sacrifice code quality in the view than in the data storage model. The last one is more important and more centrally used.
I would not be too concerned with messing up the view by calling the DAL from it or the like. Changes in a view are localized and do not mess up the application's architecture. They just degrade the view.
Maybe you could create a view model in your controller and do the translations between DAL-model and view model? Or is that pattern not allowed?
I'm building a DAL for a widget-based reporting application, its been designed in such a way that users pick, configure and deploy reporting 'widgets' to their home screens. Widgets can report across various kinds of company data - sites, brands, employees and so on.
Whilst all users can access all the widgets/reports, all users are not authorised to access all data. If I work for Company-A I can't view sales reports for Company-B or staff attendance data for a salesman at Company-C, however I can configure such a report and add it to my 'dashboard'.
At runtime, an intermediate 'DataService' class has the job of checking the user's credentials and, if access is permitted, returning the appropriate object collection to the client.
On the initial build I just returned an empty List if access to the data was not allowed, but this is also what I do if no data is returned by the report (which can happen). I'd like to show an 'Access Denied' message on the front end if the user isn't authorised to view the data but obviously if all I get back in either eventuality is an empty collection its impossible to know if this was because of insufficients rights or just no data.
I'd be grateful if you could suggest a way of coding around this, my first thought was to move the credential-checking into another object which in turn calls the data access class but time constraints mean this isn't an option.
The only thing I can think of, which goes against everything I've ever learnt, is to throw a custom exception e.g. InsufficientApplicationPrivilegeException if access isn't granted, but this smells bad.
Thanks for reading.
I think you have a couple of options. One is to make a composite object that your data service class returns. The composite object looks something like this: -
class DataResult<T>
{
IEnumerable<T> Data;
Result ServiceResult;
}
ServiceResult contains metadata about the outcome of your service call - it could be an enum which contains e.g. Success, AuthenticationFailure etc. etc.. You can then switch on this in order to do different behaviour.
An alternative option might be to use the NullObject pattern that shows a single item of data in the view which instead of real data simply shows "Access Denied" for the display properties of the object. The advantage of this approach is that your front-end doesn't need to have any conditional logic etc.; however if you want to show a specific message box or similar rather than just displaying a dummy row of data in your widget, then this probably isn't appropriate.