My Last Retrospective: Lessons and Thoughts during my Time in Southworks
Filed in Retrospectives, Uncategorized, October 1, 2009, 7:20 pmEvery beginning has an ending, everything is impermanent, and that’s what is happening to me and my friend Southworks. It was not a sudden decision; the seed of change was sown some time ago. All the objectives and perspectives I envisioned in the past have now been fulfilled. The conditions have met, no strains attached, so it’s time to let this seed flourish. I’m also leaving my family, my friends, my favorite places, my dog, almost all my personal belongings, in turn of a quiet place to think and gain more knowledge about myself and my mind. I will never forget the important role Southworks played during these four years to make this trip possible, so may these words express, at least a little, how grateful I am of having the chance to grow as a professional and as a human in this place.
So what did I learn in these four years? This question is really important in several ways. First, it is always useful to retrospect from what you have done, it helps to improve, and give us an idea of where are we standing. Second, it is an opportunity to know more about yourself, and to set expectations for the future to come. The difficult part is that we tend to avoid stopping the ball, looking back. We are like prisoners of time in a sense that we run constantly, everything is for tomorrow, and we feel the deep need to look forward, and be there, grab more. This idea is so attached in our spirit that sometimes we forget to be in the present, to look deeper in our minds for answers, to be conscious of ourselves. It’s not free to change this behavior; in fact it requires a lot of effort, and practice. This is what Southworks provided, a framework in which I can progressively develop my mind to break old and obsolete paradigms. Every Friday was Retrospective day, a day to think, to talk with the team, to learn from the present time, to uncover ghosts, things that I usually escaped from. I consider this a really huge learning.
Have you ever wondered how are you communicating with others? Are you being clear? Do others understand what you want to say? Are you really helping the other person or are you creating another problem? If you had the chance to be in Southworks’ office for a moment you will inevitably breathe this air of concern for the other. Written and oral communication is another core aspect of Southworks philosophy, and as many of the other cores, it is intended to become more conscious of our acts. I would rather call it altruistic communication because it is crucial to think in terms of the other, try to express in a way that the other can understand, no matter if it takes more time. This idea lies behind the concept “Easy to Work With” which means that we have to make the others life easier. When I looked deeper into this idea of altruistic communication, I realized that it had much to do with breaking the old concepts I have mentioned before. It is a technique to weaken the self-centeredness we have been building since we were young, and in my personal experience, it is not a healthy habit at all. It forced me to put others before me every day, which was not an easy task, but with some practice I can say that now it flows more naturally and makes me feel much better after sending an email. I consider this practice a key starting point for cultivating generosity. On the other hand, it also helped me to structure my ideas more efficiently, to prioritize content, to expand my vocabulary, and above all to feel comfortable while writing or conceptualizing information to someone else.
Working with people is complex. Each of us has our own mental models that may not be compatible with other mental models, many established prejudices that surely narrow our ability to perceive things, and certainly our own way of doing things. Some are more technically prepared than others or are even more capable and agile to process concepts. This kind of gap can also bring side effects. Additionally, people carry a luggage of private life matters that can affect and condition their entire work day, and this is inevitably spread across the office, at least in a subtle level. All this apparent friction that may emerge as a consequence of people interaction can be smoothed with a deep and honest understanding of team work. Team work does not necessary mean that people must be in the same team, it is rather a state of mind that includes anyone that needs help. In my personal experience, this was a radical change of paradigm in the way I used to relate to people. It is a different approach in my commitment to others. A friend inside Southworks once told me “If you help that guy with all that you have by transferring him all your knowledge and by taking the right time to explain, not just a solution, but the real causes that lie behind the problem, you will also be helping yourself“. You can call it karma team work or you can use the term that you like, but it is just simple math. If the guy really learns the lesson, he will now be capable of solving his own problems, and therefore will not go for you when a similar problem arises; so with more autonomy over here and less problems over there, we have more success in the overall, just simple math I told you. Apart from that, this autonomy will save your precious time which is a lacking resource, and will allow you to take care of other critical stuff that really require your attention. And moreover, if you encourage him to apply this attitude with others, the phenomena will grow exponentially, and undoubtedly you will feel a different vibe in the office. I believe that this way of thinking is the foundation for a healthy and prosper community, and that is what Southworks is doing. These kinds of teachings are the ones that make me proud of being part of this company, because they can be applied not just inside the office, but in every aspect of life.
Although these good practices are aimed to be more customer oriented, to increase our work efficiency, and above all to become a better professional, I believe that they also carry the potential to make you a better person; it is all in our hands. I feel privileged to have worked and learned from guys who I consider the best in what they do. They are always looking forward to improve and making the difference; that is the heart of a Southy. I sincerely hope that you keep growing, educating people, and crossing the limits to make this a better world for every living being; at least that is what I will be doing from my side.
Thanks again,
Ezequiel Bella “Easy –b”
Federated Identity Concepts and Patterns
Filed in Uncategorized, February 16, 2009, 8:39 amLast week I’ve read an excellent set of articles that were published in the Architecture Journal #16 (Identity and Access), and deeply caught my attention the way in which the authors expose in a really simple way most of the concepts you need to have in handy to face this new era of security.
In order to internalize most of the concepts, I’ve made a summary of the articles I’ve read so far, so I can get the big picture again when my memory needs so; and now I’m sharing this with you. Remember to read the full article to get into more detail!
The Evolving Role of Identity (by Fernando Gebara Filho)
(Source: http://msdn.microsoft.com/en-us/architecture/cc837112.aspx)
Phases of Identity during the last years
- Punched Cards (UserName and Password in the card)
Reason to Evolve: Low Secure
- Workgroups (each workgroup member responsible for security checking)
Reason to Evolve: Not integrated in the network
- Workgroups with network credentials (identity database replicated among all workgroup members)
Reason to Evolve: Inconsistencies from replication + heavy payload
- Network Domain (all network members managed by a central credential database)
Reason to Evolve: Model did not support trust relation between domains under different technologies
- Identity Federation Systems (cross platform, standardized set of protocols to transmit identities among loosely coupled domains)
Federated Identity: Patterns in a Service oriented World (by Jesus Rodriguez and Joe Klug)
(Source: http://msdn.microsoft.com/en-us/architecture/cc836393.aspx)
Principles of Web Service Federation
STS: Isolated service that removes the dependencies between company services and the authentication mechanism
- Provides ClaimSets: Assertions about the consumer’s identity (name, age, email)
- Issue Security Tokens
- Services and IP/STS are part of the same Trust Domain.
- Consumer then uses tokens issued by STS to consume the services.
- Service authenticate consumer using both Tokens and claimsSets.
Initial Federation Challenge (The problem that Federation comes in to solve)
How to communicate the Consumer and the Service if they live in different Trust Domains?
Patterns
Inter-Domain Token Exchange
Context:
- The Consumer belongs to a different Trust Domain (A) than the Services (Federated Trust domain B) he wants to consume.
- The service only allows calls to valid tokens issued by the IP of its Trust Domain (IP/STS B).
- Consumer can only authenticate through IP/STS A, but the Service has not knowledge about that authentication mechanism
- We need to find a way in which the Service can understand the Consumers credentials.
Characteristics (Forces):
- Multiple Identity Providers: Your company needs to maintain different multiple trust domains for scalabilty and management reasons (IP/STS A and IP/STS B may issue tokens in different format)
- Trust Boundaries: Service only accepts tokens issued by the IP/STS of its Trust Domain.
Solution:
- Provide a Trust relationship between the two identities. This way IP/STS B will trust the security tokens issued by IP/STS A.
- Customer will communicate with IP/STS A telling that wants to access to resources on Trust Domain B.
- IP/STS A will issue a set of tokens and identity claims that IP/STS B will understand and allow the Consumer access to the Service.
Pros:
- Keeps Trusts Domains isolated
- Extensible to more complex federated scenarios
Cons:
- Generates certain dependencies between the Consumer and the IP/STS B
- If IP/STS B issue tokens as certificates the Consumer will have to implement some logic to handle them (see Intra-Domain Token Exchange pattern to a solution to this drawback).
Intra-Domain Token Exchange
Context:
- Similar to Intra-Domain but avoiding dependencies between the Customer and the IP/STS B
Characteristics (Forces):
- All the ones from the previous scenario.
- Different token claims representation: IP/STS B issue tokens that can’t be handed by the Consumer application (cant’ change the consumer logic to implement the handing)
Solution:
- The Consumer presents the token acquired in the IP/STS A directly to the Service in the Trust Domain B.
- Service implements some sort of interceptor to forward the claims and tokens to IP/STS B.
- IP/STS B will use the authentication mechanism of the trust relationship to validate the tokens.
Pros:
- Removes dependencies between Consumers and IP/STS from other Trust Relationships.
- Suitable for very secure scenarios where the Consumer should not hand security tokens issued by IP/STS in the other trust domain. (For ex: Banking)
Cons:
- Introduces extra complexity while developing the authentication mechanism for the trust relationship
Third-party Trust Establisher
Context:
- Trust relationships between IP/STSs bring tightly couple interactions
- We need an approach that does not alter the natural behavior of the IP/STSs
Characteristics (Forces):
- Policy Change Frequently: Policies that regulates the identities with the Consumer changes frequently. Those changes can influence the policies of the other IP/STS (IP/STS A decides that now on the claims issued to users should exclude the bank account; however IP/STS B still needs this claim to authenticate)
- Different Token-Claims representation: Similar to the previous pattern
- Loosely Coupling IP/STSs: One IP/STS should not have knowledge of the authentication mechanism of the other IP/STS
Solution:
- Establish a trust relationship using a third party (IP/STS C) to act as a bridge between both trust domains
- Consumer will request a token to IP/STS A
- IP/STS A will contact IP/STS C that will issue a token that IP/STS B will understand
Pros:
- No dependencies between IP/STSs in terms of authentication mechanism
Cons:
- The third party is a new component that must be versioned and maintained
Pseudonym Claim Service
Context:
- Some scenarios require keeping the real identity of the caller hidden while calling a Service in a different Trust Domain. (identity not propagated across domains)
- Identity Mapping is needed within the Consumer trust domain
Characteristics (Forces):
- Identity Protection: Protect the identity across different Trust Domains.
- Identity Mapping: Trust Domains may represent identities and attributes differently. This is a mechanism that translates identities from one trust domain, to be understood by the other trust domain.
- Identity Collision: The identity of Services within a IP/STS can collide with other identities in a federated Trust Domain.
Solution:
- Implement a Pseudonym Claim Service to map the real identities to pseudonyms.
- These pseudonyms will be the identities that the Consumer will use to call the Service.
- The IP/STS B will generate the claims and security tokens based on those pseudonyms identities.
- Then the identity flow goes on as usual, using any of the patterns seen before.
Pros:
- Preserves the real identity across Trust Domains.
- Given that the aliases are applied to the initial claim set, the identity mapping process can be executed against the aliases with no impact to the process.
Cons:
- Pseudonym Claim Service is another component you need to maintain (including the pseudonyms mapping database)
Attribute Claim Service
Context:
- Sometimes the federation procedures require extra information than the one generated in an IP/STS (IP/STS B requires more claims than the ones IP/STS A is issuing to the Consumer)
- This may not mean that IP/STS A do not have that information, but due to privacy policies cannot issue them directly to the Consumer.
- IP/STS B may need for example email claims that are not part of the original claimset generated by IP/STS A.
Characteristics (Forces):
- Privacy: Based on privacy requirements, only a subset of the Consumer claims is issued as part of the identity information issued by the IP/STS (A). The Consumer cannot handle certain claims that may be considered delicate by the issuer entity.
Solution:
- The remaining Consumer claims (needed by the other IP/STS (B)) may be accessible to security entities such as IP/STSs , but should not be propagated to the consumer applications.
- The attributes needed for identity federation can be exposed through an Attributes Claim Service, which can be invoked from any security entity (Service or IP/STS depending on the pattern chosen).
- In order to complete the federation process, IP/STS B may need some extra claims that are not present in the original security token, so a service call is made to the Attribute Claim Service (ACS).
- IP/STS B would obtain these claims presenting to the ACS the original claims issued by IP/STS A to the Consumer, and its own security identity.
- The trust relationship between IP/STSs allows IP/STS B to communicate with the ACS.
Pros:
- Preserves privacy within a Trust Domain, and avoids changing the privacy requirements just to access a different Trust Domain.
- This pattern can be applied in different topologies, and can be combined with pseudonym service pattern.
Cons:
- ACS is another component you need to maintain (including authentication mechanism with other IP/STS that invoke it)
Defederation
Context:
- Sometimes you may want to eliminate the relationship that exists between entities within a Federated Solution (Identity Providers, Services, and Consumers). For ex, remove the association between the Consumer’s principal accounts with the IP/STS B; this will result in the impossibility for the Consumer to invoke the Services in the other Trust Domain.
- The governance and management of entities involved in the Federation is absolutely vital to the correct functioning of the model.
Characteristics (Forces):
- Defederating Services: When a Service is removed from the federation, we need a mechanism to dynamically update the IP/STS and other services in the federation Trust Domains that have a relationship with that Service.
- Defederating Consumers: Notify the IPs that the claims from that Consumer are not longer valid.
- Updating Policies: When the security policy of a service changes, we need a mechanism for propagating those changes to the federated IP/STSs.
Solution:
- Provide the entities involved in a federation with a publish/subscribe “defederation protocol†that can be used as a mechanism for Defederating entities.
- For instance, when a Service is removed from the federation, a “Defederated Service†message is sent to the IP/STS of its Trust Domain, and from there propagated to the other IP/STS and services involved in the federation.
Pros:
- Helps to enforce the security and trust boundaries consistently.
Cons:
- Complexity in implementation
Is worth to make clear that all the merit goes to the authors of these articles; thank you guys for making me understand.
Deploying and Consuming a SQL Server 2008 Report from a SharePoint 2007 site
Filed in SQL Server 2008 Reporting Services, SharePoint 2007, October 9, 2008, 8:53 pmIn this post you will learn how to deploy a report from a SQL Server 2008 Business Intelligence Development Studio Report Server Project into a SharePoint 2007 site (Integrated with Reporting Services). Once the report is deployed, you will be able to consume it directly from a page of your SP site using a built-in web part that comes with the Microsoft SQL Server 2008 Reporting Services Add-in.
If you are still stuck in the part where you integrate Reporting Services with SharePoint 2007, you might be interested on reading my previous post Integrating SQL Server 2008 Reporting Services with SharePoint 2007.
Deploy your report from Visual Studio into your SharePoint site
This task assumes that you have already designed a report in SQL Server Business Intelligence Development Studio (Visual Studio), and you are willing to publish it into your site’s Report Gallery. In this task you will learn how to configure the report deployment settings in order to point them to the correct SharePoint URLs. For more information, see How to: Publish a Report to a SharePoint Library from Report Designer (SharePoint Integrated Mode).
1. In Solution Explorer, right-click the Report Server project, and select Properties.
2. In your report project Property Pages, edit the following fields, and click OK. (For more information on this, see Deploying Models and Shared Data Sources to a SharePoint Site):
TargetDataSourceFolder: Is the URL of your SharePoint library for shared data sources. For example: http://<siteurl>/Documents
TargetReportFolder: Is the URL of your SharePoint site for Reports. For Example: http://<siteurl>/ReportsLibrary
TargetServerURL: Is the URL of your SharePoint site to which the project is deployed. For Example: http://<siteurl>
3. Right-click the report that you wish to publish, and click Deploy.
If everything goes fine, the output should look like this:
4. Go to the Reports Library of your site, and check that the Report was successfully deployed.
Enable the Report Viewer Web Part in SharePoint
In this task you will add the Report Viewer Web Part to your site’s Web Part Gallery. Once the web part is uploaded into the Gallery, you will be able to use it from any page of your SharePoint site. Before adding it check if the Report Viewer Web Part isn’t already in your Gallery; in this case you can skip this step.
1. Navigate to the Site Settings page of the site where you wish to consume the report. To do this, click Site Actions | Site Settings | Modify All Site Settings.
2. In the Galleries section, click Web Part link.
3. Upload the Report Viewer Web Part (installed by the Add-In Microsoft SQL Server 2008 Reporting Services Add-in for Microsoft SharePoint Technologies) to the site’s Web Part Gallery. To do this, click Upload | Upload Document.
4. Click Browse, point to “C:\Program Files\Common Files\microsoft shared\Web Server Extensions\12\TEMPLATE\FEATURES\ReportServer\ReportViewer.dwp”, and click OK.
5. In the Web Part Gallery Edit Item page, accept default values by clicking OK. The Web Part should now be visible in the Web Part Gallery list.
Consume the report from a Page in your SharePoint Site.
This page will contain the built-in web part that will consume the Report. For more information, see
1. Create a new page in your SharePoint site. To do this, click Site Actions | Create Page.
2. Configure the new Page Title and URL, and select the template that supports web parts named (Welcome Page) Blank Web Part Page. Then click Create.
3. Click Add a Web Part in any of the allowed slots.
4. In All Web Parts, in the Miscellaneous section, select SQL Server Reporting Services Report Viewer, and click Add.
5. Edit the properties of the report in the tool pane:
6. Assign the Report target URL. To determine the URL for any report, right-click the report in the Reports Library, and select Copy Shortcut. Then paste the URL in the Report field (replace the "%20" URL encoding with a space), and click OK.
You should now see the report automatically generated in your page:
Next, you should publish the page and browse it to see the report finally working!!:)
References:
Publishing Reports from Report Server in Sharepoint Integrated Mode throws error - TechNet Forums
How to: Publish a Report to a SharePoint Library from Report Designer (SharePoint Integrated Mode)
Integrating SQL Server 2008 Reporting Services with SharePoint 2007
Filed in MOSS, Reporting Services, SharePoint 2007, October 8, 2008, 6:36 pmThis walkthrough assumes that you have previously installed MOSS 2007 (with Reporting Services Integration feature on) + SQL Server 2008 on Windows Server 2008. If you are using another Windows version, there might be steps that will slightly differ while configuring them, so try to adjust them to your environment.
Install the Microsoft SQL Server 2008 Reporting Services Add-in for Microsoft SharePoint Technologies (here).
This add-in basically provides a Report Viewer Web Part that provides report viewing capability, export to other rendering formats, page navigation, search, print, and zoom.
Configure the Report Server via the Reporting Services Configuration Manager tool.
- Service Account tab: In this scenario we will use Network Service as the service account.
- Web Service URL tab: Use the default ReportServer Virtual Directory (is already created). This is the URL of the Report Server that will be hosted in IIS. If you want to change the name, edit the Virtual Directory text and click Apply. This will remove the existing server, and do the necessary stuff to publish the new one.
- Database tab: Use the default ReportServer database (is already created). Have in mind that this database was created in Sharepoint Integrated Mode, thus cannot be accessed by the Report Server unless the database has been granted rights to access to the Sharepoint server farm (you will configure this later.)
- Report Manager URL tab: This tab is intended to configure the Report Server Control Panel. In our case, we won’t use this feature because is not supported while operating in SharePoint Integration mode.
For the other tabs, let’s use the default configuration.
Configure Report Server in SharePoint Central Admin Tool.
This step will finally integrate Reporting Services with SharePoint.
- Open the Central Administration Site. To do this, click Start | All Programs | Microsoft Office Server …
- Enable Report Server Integration Feature from SharePoint.
- Give Report Server permission to access the database in the SharePoint farm. To do this, go back to Application Management page, locate the Reporting Services section, and click the Grant database access link. Choose the appropriate db server name, choose Default Instance and click OK. You will be prompted for a user account and a password, use a System Administrator account.
- Register the Report Server URL so as to integrate it with SharePoint. In the Reporting Services section click Manage integration settings, and set the following values:
a. Report Server Web Service: Is the URL were the report server is hosted (http://<server-name>/ReportServer)
b. Authenticated Mode: Trusted Account.
-
If you will consume a report that logs on to the database using Windows Authentication, you should set this value to Windows Authentication instead.
- You can also configure the Reporting Services Server Defaults, but we will leave it like this for now. If you want to configure them see the references below for more detail.
You can verify the procedure by navigating to the ReportServer URL, and see that you are now able to browse the site correctly. This means that Report Server has the rights to access to the Report Server database of the SharePoint site farm, an operation that we were not able to perform before.
In the next post you will see how to deploy a report from Visual Studio into your SharePoint site, and then consume it using the Report Viewer Web Part that comes with the Microsoft SQL Server 2008 Reporting Services Add-in.
References:
- How to: Configure Report Server Integration in SharePoint Central Administration
- Microsoft SQL Server Reporting Services - Installation and Configuration Guide for SharePoint Integration Mode.docx
.NET 3.5 Extensions Training Kit Released!!
Filed in Uncategorized, April 14, 2008, 3:36 pmFor the past five weeks I’ve been working on a project for DPE (Developer and Platform Evangelist) to deliver a set of quality Hands on Labs consisting on the new technologies for .NET 3.5 Extensions; these includes:
- ASP.NET MVC
- Creating ASP.NET MVC Applications
- Developing ASP.NET MVC applications with TDD
- Using ASP.NET MVC along with an IoC container
- ASP.NET Dynamic Data
- Creating a data-driven web application
- Customizing an ASP.NET Dynamic Data application
- ASP.NET AJAX History
- Adding history points to an ASP.NET AJAX Web application using server controls
- Adding history points to an ASP.NET AJAX Web application using the AJAX API
- ASP.NET Silverlight controls
- Adding Rich Media to Web applications
- Hosting Silverlight Content within an ASP.NET Application
- ADO.NET Data Services
- Creating and consuming ADO.NET Data Services
- Consuming ADO.NET data services using ASP.NET AJAX API
- Extending Data Services with Service Operations and Interceptors
- ADO.NET Entity Framework
- Creating and Consuming an Entity Data Model
Get them from here!
We worked really hard to make them easy to follow and have control of what you are doing at any time.
Hope you enjoy them and find them useful as you expected!
VSTO: Populate a Word 2007 Ribbon dynamicMenu control at runtime using C#
Filed in Office 2007 Interop, VSTO, Word 2007, September 29, 2007, 9:38 pmIn this opportunity I will show you how to use the VSTO Ribbon dynamicMenu control to programmatically add controls at runtime using C#.
The dynamicMenu is a Ribbon control that has a similar behavior to the menu control, with the difference that the former allows to add controls like buttons, menus, toggleButtons at runtime. For this, it provides an attribute named GetContent which can be set to a callback that will retrieve all the data representing the menu content (For more information, see List of all callbacks and signatures).This data is no more than an XML file that nests controls in a given hierarchy and will be then recreated by the dynamicMenu.
As shown in the above figure, our goal is to dynamically generate the content XML file each time the GetContent callback is executed.
The sample code
I’m attaching in this post a ready to go sample that you can download and use to play around. Basically, it implements the GetContent callback, reads the My Documents folder from the file system and generates the content XML file. In order to reproduce a proper hierarchy we will need to distinguish files from folders and create controls accordingly. We will use menu controls to represent directories as they can act as containers for other controls, and for the files we will use buttons.
Let’s see a little bit of code…
- When the GetContent callback is executed we will call GetMenuContentFromFS that will go through the directories progressively and finally build the XML content file.
public string GetContent(Office.IRibbonControl control) { return GetMenuContentFromFS( Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)); } private string GetMenuContentFromFS(string path) { StringBuilder contentStringBuilder = new StringBuilder( @"<menu xmlns=""http://schemas.microsoft.com/office/2006/01/customui"" >" ); //append nested directories with its files AppendDirectoryContent(new DirectoryInfo(path), contentStringBuilder, 4); //append the files that are at the root level AppendFilesContent(new DirectoryInfo(path), contentStringBuilder); contentStringBuilder.Append(@"</menu>"); return contentStringBuilder.ToString(); }
- AppendDirectoryContent is a recursive method that appends a menu control for each directory that finds, and leaves the menu tag open until the directory has no more directory or file childs.
//maxDirDepth specifies the maximum level of nested menus that the controls supports private void AppendDirectoryContent( DirectoryInfo dirInfo, StringBuilder contentStringBuilder, int maxDirDepth) { if (maxDirDepth > 0) { foreach (DirectoryInfo dir in dirInfo.GetDirectories()) { string folderId = String.Concat("a" + Guid.NewGuid().ToString()); ; contentStringBuilder.Append( String.Format(@"<menu id=""{0}"" imageMso=""Folder"" label=""{1}"">", folderId, dir.Name)); AppendDirectoryContent(dir, contentStringBuilder, maxDirDepth - 1); AppendFilesContent(dir, contentStringBuilder); contentStringBuilder.Append(@"</menu>"); } } }
- AppendFilesContent method in contrast, appends a button control for each file. In this example we will just work with .docx files to make things simpler. Since all our files will be docx it will be nice if we can change the button icon to have word’s; we can do this by setting the button’s imageMso attribute to FileSaveAsWordDocx.
The button control also provides an OnAction attribute were you can set a callback that is executed every time the button is clicked. We will implement this callback later.After appending the control we will relate the control id (fileId) with the file path for future usage.
private void AppendFilesContent(DirectoryInfo dir, StringBuilder contentStringBuilder) { FileInfo[] files = dir.GetFiles("*.docx"); foreach (FileInfo file in files) { //the control id cannot start with a number string fileId = String.Concat("a" + Guid.NewGuid().ToString()); contentStringBuilder.Append( String.Format(@"<button id=""{0}"" label=""{1}"" onAction=""OnAction"" imageMso=""FileSaveAsWordDocx"" />", fileId, file.Name)); filePaths.Add(fileId, file.FullName); } }
- Finally, we will implement the OnAction callback. Here you can do what you want, open the file, paste it in word. We will just display the full file path to keep the sample simple.
public void OnAction(Office.IRibbonControl control) { object oObject = System.Reflection.Missing.Value; Microsoft.Office.Interop.Word.Application applicationObject = ((Word.Window)control.Context).Application; string filePath = filePaths[control.Id]; System.Windows.Forms.MessageBox.Show(filePath); }
An important thing to have in mind is that the normal behavior of dynamicMenu control is to execute the OnAction callback just the first time you click on it. So if you add or remove some files to the My Documents folder you won’t see the changes until you reopen the document. But this behavior can be changed to have the callback executed every time we click on the dynamicMenu :).
Here is the trick: You need to invalidate the dynamicMenu control in the Application.WindowActivate event and force it to reload.
void Application_WindowActivate( Microsoft.Office.Interop.Word.Document Doc, Microsoft.Office.Interop.Word.Window Wn) { ribbon.ribbonUI.InvalidateControl("dynamicMenuSample"); }
If you have some time, download the sample and see it working.
See you in the next post!
Greetings Hernan Rey-Willis, Southworks’ new CEO!!
Filed in Uncategorized, September 25, 2007, 1:26 amSouthworks’ family is getting bigger and bigger as days pass, and makes me wonder if there is a limit. In this opportunity I would like to introduce our new CEO, Hernan Rey-Willis, who decided to join us in the path to greatness. I’m sure he will bring Southworks tons of energy and positive vibrations! =)
Cheers southies for this important milestone!¡!
Hernan Rey-Willis performing his speech
Southworks family!
Office Interop: Attach a custom template and update styles in Word 2007 using C#
Filed in Office 2007 Interop, VSTO, Word 2007, September 22, 2007, 7:44 pmHi, in this opportunity you will see how to attach a given template into a Word 2007 document programatically (C#), and subsequently update the styles that were modified.
Sample Solution
If you like to see the code working, I’m attaching in this post a really simple sample solution that you can download and use it at will. The sample consists on a VSTO Word 2007 add-in solution that when debugs it opens a Word 2007 instance. This Word 2007 instance has plugged-in an additional ribbon bar with one button named AttachTemplate that will attach a provided template every time it is clicked.
The Code
The code is really small and seamless; seems that the guys of Interop did a great job with this :). First of all, we need to gather the active Word Document which is the object representation of our Word document instance (For more information, see Document Interface).
The Document interface exposes two methods that comes in handy for our mission: set_AttachedTemplate and UpdateStyles. When we call the set_AttachedTemplate, Interop resets the Document.AttachedTemplate property and performs additional tasks such as manipulating the Styles section of the OpenXml (more precisely the word\styles.xml XmlPart).
(For more information, see AttachedTemplate property)
At this moment, all elements that compose a template have been re assigned to match the new ones, but you won’t see any style changes. The document content and the styles pane will stay unaltered. Here is when UpdateStyles method comes into action by adding the new styles into the style pane and forcing all the document content styles to get updated instantly.
See it by yourself:
private void AttachTemplate(Word.Document document, string templateFilePath) { object oTemplate = (object)templateFilePath; document.set_AttachedTemplate(ref oTemplate); document.UpdateStyles(); }
Hope it helped!
See you!
Office Interop: Convert Word 2007 text into a Plain Text Content Control using C#
Filed in Office 2007 Interop, VSTO, Word 2007, September 15, 2007, 8:47 pmIntroduction
In order to make the sample more exciting, you will convert a text selection into a plain text content control. For this, you will use several Interop interfaces such as Selection and Range, but don’t panic because their use is really simple and intuitive. For more information, see Selection Interface and Range Interface.
Additionally, I’m attaching in this post a solution sample containing the full code that you may use as a guide for this walkthrough. It consists on a Word 2007 VSTO solution that when runs it opens a Word 2007 instance and creates a custom Ribbon with one button named ConvertText. When this button is pressed, it converts the current selected text into a plain text content control.
Requirements to run the code sample
- 2007 Microsoft Office system Primary Interop Assemblies
- Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office System
The code
Let me briefly describe the big picture. When the ConvertText ribbon button is clicked, a callback named ConvertText_Click is called.
This method simply checks if there is any text selected in the active Word 2007 instance and if indeed, it calls to CreateContentControlInSelection method that converts the selection into a plain text content control.
The code is really simple and self-explained:
public void ConvertText_Click(Office.IRibbonControl control) { Selection selection = ((Word.Window)control.Context).Application.Selection; int selectionLength = selection.Range.End - selection.Range.Start; if (selectionLength > 0) { if (CreateContentControlInSelection( selection, TOPIC_TITLE, DateTime.Now.ToString()) != null) { object oUnit = WdUnits.wdCharacter; object oCount = selectionLength + 1; //Gets out of the content control selection.MoveRight(ref oUnit, ref oCount, ref paramMissing); } } } private ContentControl CreateContentControlInSelection( Selection selection, string controlName, string controlTag) { ContentControl contentControl = null; if (selection.Paragraphs.Count > 1) { MessageBox.Show( "Plain text conent control cannot be inserted around multiple paragraphs.", "Microsoft Office Word", MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { object oRng = (object)selection.Range; contentControl = selection.Range.ContentControls.Add( WdContentControlType.wdContentControlText, ref oRng); if (contentControl != null) { contentControl.Range.Text = selection.Text.Replace("\r", ""); contentControl.Tag = controlTag; contentControl.Title = controlName; } } return contentControl; }
How to run the sample?
- Download the sample from this post.
- Unzip the AddContentControl.zip file
- Double click the AddContentControl.sln solution file.
- Hit F5 to run the solution and start a new Word 2007 instance with the RibbonBar add-in.
- Enjoy!
Stay tuned!
OpenXml: Export and resize Word 2007 embedded images with C#
Filed in .NET 3.0, OpenXml, VSTO, Word 2007, August 23, 2007, 8:00 pmHi to all! In this post I will show you how to programatically (C#) export the images that are embedded in Word 2007. As you may know, all the images that are inserted into Word are also embedded as document parts.
All embedded parts in a Word 2007 document are in their native, default Word XML format. Therefore, if you add a picture to a document, you can rename the document with a .zip extension, and open it as you would any ZIP file. Within the package, you can locate the picture and open it as well. If the picture is in a .png format, you can see and open a .png file directly from the package.
Requirements
You will need the following technologies to use this piece of code:
-
.NET Framework 3.0 -> You will need to use the System.IO.Packaging Namespace. For more information, see System.IO.Packaging Namespace.
Inside the code
Before starting, have in mind that this is not intended to be an OpenXml tutorial. If you want to learn more about OpenXml standard and characteristics visit, Walkthrough: Word 2007 XML Format.
In the following section I will show and explain the functionality of one method named ExportEmbeddedImages that contains the most relevant logic you need to know. If you want to explore the code more deeply, please download the entire solution attached in this post.
Pretty much of the implementation of this post is inspired on the 2007 Office System Sample: Open XML File Format Code Snippets for Visual Studio 2005. It really helped me to start thinking in terms of PackageParts and PackageRelationships.
ExportEmbeddedImages method
In this method we will open the docx file as a Package to retrieve the main document part (word\document.xml), where we can find all the image relationships (represented by the PackageRelationship class).
Then we will loop over the image relationships and will get the image PackagePart that is actually the embedded image stream. We will resize the PackagePart using the Bitmap class and finally save it to disk in png format.
-
First of all, we need to open the Package, which is the object representation of the docx file. The package is basically a container of PackageParts and PackageRelationships. For more information, see Package Class (System.IO.Packaging).
using (Package wdPackage = Package.Open(documentPath, FileMode.Open, FileAccess.Read)) -
Once we opened the docx Package, we need to retrieve the main document part (document.xml). This PackagePart contains the main document information such as the document paragraphs, images, styles, bookmarks, etc.
PackagePart documentPart = GetMainDocumentPart(wdPackage);
-
Get the image PackageRelationships from the main document part and loop over each of them. A relationship is a logical connection between two parts within the file package. In this case, the relationship specifies the physical location of the image within the package.
const string imageSchema = @"http://schemas.openxmlformats.org/ officeDocument/2006/relationships/image"; foreach (PackageRelationship imageRel in documentPart.GetRelationshipsByType(imageSchema))
-
Check if the relationship corresponds to an embedded image by accessing to the TargetMode.External enum.
if (imageRel.TargetMode != TargetMode.External) -
Get the image size from the main document part which will be used to resize the original embedded image. Remember that images are embedded in its original size as PackageParts, so if you resize the image from Word, they will not be altered at all. That’s why you need to manage the image size separately from the main document part.
Size imageSize = GetEmbeddedImageSize(documentPart, imageRel.Id); -
By default, sizes in OpenXml packages are stored in a unit named EMUs (English Metric Units), so we will convert it to pixels which is the unit that the Bitmap class understands. We will use Bitmap class to save images to disk.
imageSize.Width = ConvertEmuToPixels(imageSize.Width); imageSize.Height = ConvertEmuToPixels(imageSize.Height);
-
Finally, we will call the ExportImage method that will resize the original image and will save it to disk. Basically this method uses the image relationship to obtain the PackagePart that contains the original image stream and resizes it using the size managed in the previous step.
ExportImage(imagesPath, documentPart, imageRel, imageSize);
Here you have the complete method:
internal static void ExportEmbeddedImages(string documentPath, string imagesPath) { using (Package wdPackage = Package.Open(documentPath, FileMode.Open, FileAccess.Read)) { PackagePart documentPart = GetMainDocumentPart(wdPackage); if (documentPart != null) { const string imageSchema = @"http://schemas.openxmlformats.org/ officeDocument/2006/relationships/image"; foreach (PackageRelationship imageRel in documentPart.GetRelationshipsByType(imageSchema)) { //is an embedded image if (imageRel.TargetMode != TargetMode.External) { Size imageSize = GetEmbeddedImageSize(documentPart, imageRel.Id); if ((imageSize.Width > 0) && (imageSize.Height > 0)) { imageSize.Width = ConvertEmuToPixels(imageSize.Width); imageSize.Height = ConvertEmuToPixels(imageSize.Height); ExportImage(imagesPath, documentPart, imageRel, imageSize); } } } } } }
Running the sample
To run the sample:
- Download and build the solution attached in this post
- Execute the ExportEmbeddedImage.exe in a command prompt with the following parameters:
- documentPath: Specifies the path and name of the docx
- imagesPath (optional): Specifies the images output path
See you in the next post!