Bing Main search page. MSN Main Page
Bing Webmaster Tools Use the Bing™ Webmaster tools to improve your site's SEO, submit your sites and XML-based Sitemaps to Bing, get data on which pages of your site have been indexed, backlinks, inbound links and keyword performance.
Schema. A site that provides a collection of schemas, i.e., html tags, that webmasters can use to markup their pages in ways recognized by major search providers. Search engines including Bing, Google, Yahoo! and Yandex rely on this markup to improve the display of search results, making it easier for people to find the right web pages. Many sites are generated from structured data, which is often stored in databases. When this data is formatted into HTML, it becomes very difficult to recover the original structured data. Many applications, especially search engines, can benefit greatly from direct access to this structured data. On-page markup enables search engines to understand the information on web pages and provide richer search results in order to make it easier for users to find relevant information on the web. Markup can also enable new tools and applications that make use of the structure. A shared markup vocabulary makes easier for webmasters to decide on a markup schema and get the maximum benefit for their efforts. So, in the spirit of sitemaps.org, search engines have come together to provide a shared collection of schemas that webmasters can use.
WebMatrix is a free web development tool from Microsoft that includes everything you need for website development. Start from open source web applications, built-in web templates or just start writing code yourself. It’s all-inclusive, simple and best of all free. Developing websites has never been easier.
Microsoft WebMatrix Information, a free, lightweight tool that provides the easiest way to build websites yet, using the new Razor view engine. Combined in the installation of WebMatrix are SQL Server Compact, IIS Express, and the ASP.NET Web Pages framework that includes the Razor syntax. All of these make the process of creating and deploying WebMatrix websites simple. This article will step you through the process of how to get the most out of WebMatrix and the new Razor view engine
U Rank, which requires users to sign in with a Windows Live ID before searching, allows users to edit, organize, and annotate search results, then share them with others, giving Microsoft valuable data on what people are looking for when they perform searches. A bit more about Microsoft's release of URank
from ideas to solutions
In GoingNative 2012, there are some discussions on the new coding style for C++11. One interesting thing which is mentioned by Bjarne Stroustrup, Stephan T. Lavavej and Herb Sutter is the most efficient way to pass the argument.
In C++98, pass by reference is in general more efficient because it saves extra copies (if the copy is expensive, otherwise the extra indirection may hurt the perf instead). However, after the introduction of move semantics in C++11, the story is now a little different (Note that premature optimization doesn’t buy you anything, so the following is to give you a full picture of the new thought introduced in C++11, see the guidelines at the end and use it when appropriated)
Let’s see the following example:
#include <iostream>
#include <vector>
using namespace std;
struct String {
String(const wchar_t *) {
cout << "ctor" << endl;
}
String(const String &) {
cout << "copy ctor" << endl;
}
String(String &&) {
cout << "move ctor" << endl;
}
};
void f1(String s) {
vector<String> v;
v.push_back(std::move(s));
}
void f2(const String &s) {
vector<String> v;
v.push_back(s);
}
void g() {
String s(L"");
cout << "f1(s)" << endl;
f1(s);
cout << "f1(L"")" << endl;
f1(L"");
cout << "f2(s)" << endl;
f2(s);
cout << "f2(L"")" << endl;
f2(L"");
}
If you run the code, you will find that ‘f1’ has one less copy ctor call for rvalue argument and the same amount of copy ctor call for lvalue argument than ‘f2’, which means ‘f1’ is more efficient (assume that move ctor is much cheaper than copy ctor).
The trick is as follows: for lvalue argument, ‘f1’ has one extra copy to pass the argument because it is by-value, while ‘f2’ has one extra copy to call push_back. So no difference; for rvalue argument, the compiler has to create a temporary ‘String(L“”)’ and pass the temporary to ‘f1’ or ‘f2’ anyway. Because ‘f2’ can take advantage of move ctor when the argument is a temporary (which is an rvalue), the costs to pass the argument are the same now for ‘f1’ and ‘f2’.
This means in C++11 we can get better performance by using pass-by-value approach when:
One example for the above guidelines (no copies here!):
// Assume that Matrix has a cheap move ctor
Matrix operator-(Matrix m)
{
// Manipulate m
return std::move(m);
}
Matrix m = -(a + b);
We recently did a realignment on my team due to a change of priority of projects. This was a good experience as we moved projects between QA leads so that our workload was more evenly balanced. And then we moved people around from projects that were getting less funding to those that were becoming more important. With all of this, there are many places where an individual employee and lead are now working together that hadn't before. So how did we make a smooth start to these new relationships?
I asked my leads to really know themselves, what their strengths and weaknesses are, and how they manage their teams. If they have quirks or interesting ways of leading, they need to identify those. Then be upfront in communicating those to the people who are new at reporting to them. This description of yourself as a manager is considered your managerial style. Having this discussion will allow the new team members to set expectations correctly. For example, I truly can't find the time to read all my emails and I actually dislike reading email. So I would be setting myself and my direct reports up for failure if they continue to send me lengthy, deep emails about issues and expect me to read them word-for-word and understand them. I am a much better listener than a reader. So when I join a new team, I first tell them that short concise emails are appreciated and follow-up with me in person. Without an upfront discussion about my likes and dislikes as a leader and my style for working, we would have had communication issues and lost efficiencies. So leads need to be upfront with their reports on how they work and what they should expect. Some key terminology to think about if you are trying to describe your managerial style is: are you a hands-on, directive manager or a coach? Do you like to lead by example? Do you empower others? Do you focus more communications downward, sideways, or upward? If you are a people manager, can you describe your managerial style?
The same works in reverse as well. I've heard people joke about training their manager, but this is actually a true, realistic phenomenon. As an employee, you need your manager to understand who you are, how you work, and what your desires are. A good manager will change their style to conform more with one that works for you. Different engineers need different things from their manager, so managers need to be flexible in their approaches with each employee. If your manager is making assumptions about how to work with you, delegate to you, or give you opportunities, be upfront about what you need and when you aren't receiving the right things from your boss. If you don't tell your boss what you need to building a healthy relationship with him/her and have a job you are happy with, you may find it more difficult to get on the same page with your boss in the future. Some questions you need to ask yourself before this conversation is: what are your strengths and weaknesses? What is your working style, independent or team player or mixture of both, but when? What are your career aspirations? What opportunities do you want your manager to watch out for and assign to you?
When I transferred to a new team, I got a new boss. My emails to my new boss were very friendly with lots of background info because that's what my previous boss liked. But I always liked being short and to the point so writing emails took longer as I catered to my previous manager's desires. Within the first few weeks, I found out my new boss was very similar to me and appreciated short emails that were straight to the point. What a relief! I could get so much more done once I knew how to communicate with him and that I can communicate in the style that is comfortable to me.
Even after this conversation with your new manager, continue to clarify conversations if you and your boss are saying things in different ways. The more you can learn about your boss, the better you can represent his/her interests in the work you do. And the more your boss knows about your working style, the better he/she can be at giving you opportunities. Sometimes, this training period for this type of relationship takes time. Be patient.
If you have a new boss, take some time out to find out their managerial styles, strengths, and expectations. And then explain what you are looking for or need from your manager and see if the two of you can come up with a plan that works for both of you moving forward.
I had a great question from Scott Forsyth earlier today about programmatically flushing the logs for an FTP site. Scott had noticed that there was a FlushLog method listed on the following page in the IIS Configuration Reference:
http://www.iis.net/ConfigReference/system.applicationHost/sites/site/ftpServer
Unfortunately there wasn't a code sample for that method; but as luck would have it, I had already written some code to do just that. (I love synchronicity...) With that in mind, I though that I'd post the code in a blog. In keeping with the cross-language samples that I wrote for the topics in the Configuration Reference, I thought that's I'd include several languages in this blog to make it easier for someone else to copy and paste.
using System;
using System.Text;
using Microsoft.Web.Administration;
internal static class Sample
{
private static void Main()
{
using (ServerManager serverManager = new ServerManager())
{
Configuration config = serverManager.GetApplicationHostConfiguration();
// Retrieve the sites collection.
ConfigurationSection sitesSection = config.GetSection("system.applicationHost/sites");
ConfigurationElementCollection sitesCollection = sitesSection.GetCollection();
// Locate a specific site.
ConfigurationElement siteElement = FindElement(sitesCollection,"site","name",@"ftp.contoso.com");
if (siteElement == null) throw new InvalidOperationException("Element not found!");
// Create an object for the ftpServer element.
ConfigurationElement ftpServerElement = siteElement.GetChildElement("ftpServer");
// Create an instance of the FlushLog method.
ConfigurationMethodInstance FlushLog = ftpServerElement.Methods["FlushLog"].CreateInstance();
// Execute the method to flush the logs for the FTP site.
FlushLog.Execute();
}
}
// Locate and return the index for a specific element in a collection.
private static ConfigurationElement FindElement(ConfigurationElementCollection collection, string elementTagName, params string[] keyValues)
{
foreach (ConfigurationElement element in collection)
{
if (String.Equals(element.ElementTagName, elementTagName, StringComparison.OrdinalIgnoreCase))
{
bool matches = true;
for (int i = 0; i < keyValues.Length; i += 2)
{
object o = element.GetAttributeValue(keyValues[i]);
string value = null;
if (o != null)
{
value = o.ToString();
}
if (!String.Equals(value, keyValues[i + 1], StringComparison.OrdinalIgnoreCase))
{ matches = false;
break;
}
}
if (matches)
{
return element;
}
}
}
return null;
}
}
Imports System
Imports System.Text
Imports Microsoft.Web.Administration
Module Sample
Sub Main()
Dim serverManager As ServerManager = New ServerManager
Dim config As Configuration = serverManager.GetApplicationHostConfiguration
' Retrieve the sites collection.
Dim sitesSection As ConfigurationSection = config.GetSection("system.applicationHost/sites")
Dim sitesCollection As ConfigurationElementCollection = sitesSection.GetCollection
' Locate a specific site.
Dim siteElement As ConfigurationElement = FindElement(sitesCollection,"site","name","ftp.contoso.com")
If (siteElement Is Nothing) Then
Throw New InvalidOperationException("Element not found!")
End If
' Create an object for the ftpServer element.
Dim ftpServerElement As ConfigurationElement = siteElement.GetChildElement("ftpServer")
' Create an instance of the FlushLog method.
Dim FlushLog As ConfigurationMethodInstance = ftpServerElement.Methods("FlushLog").CreateInstance()
' Execute the method to flush the logs for the FTP site.
FlushLog.Execute()
End Sub
' Locate and return the index for a specific element in a collection.
Private Function FindElement(ByVal collection As ConfigurationElementCollection, ByVal elementTagName As String, ByVal ParamArray keyValues() As String) As ConfigurationElement
For Each element As ConfigurationElement In collection
If String.Equals(element.ElementTagName, elementTagName, StringComparison.OrdinalIgnoreCase) Then
Dim matches As Boolean = True
Dim i As Integer
For i = 0 To keyValues.Length - 1 Step 2
Dim o As Object = element.GetAttributeValue(keyValues(i))
Dim value As String = Nothing
If (Not (o) Is Nothing) Then
value = o.ToString
End If
If Not String.Equals(value, keyValues((i + 1)), StringComparison.OrdinalIgnoreCase) Then
matches = False
Exit For
End If
Next
If matches Then
Return element
End If
End If
Next
Return Nothing
End Function
End Module
// Create a Writable Admin Manager object.
var adminManager = new ActiveXObject('Microsoft.ApplicationHost.WritableAdminManager');
adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST";
// Retrieve the sites collection.
var sitesSection = adminManager.GetAdminSection("system.applicationHost/sites","MACHINE/WEBROOT/APPHOST");
var sitesCollection = sitesSection.Collection;
// Locate a specific site.
var siteElementPos = FindElement(sitesCollection,"site",["name","ftp.contoso.com"]);
if (siteElementPos == -1) throw "Element not found!";
// Retrieve the site element.
var siteElement = sitesCollection.Item(siteElementPos);
// Create an object for the ftpServer element.
var ftpServerElement = siteElement.ChildElements.Item("ftpServer");
// Create an instance of the FlushLog method.
var FlushLog = ftpServerElement.Methods.Item("FlushLog").CreateInstance();
// Execute the method to flush the logs for the FTP site.
FlushLog.Execute();
// Locate and return the index for a specific element in a collection.
function FindElement(collection, elementTagName, valuesToMatch) {
for (var i = 0; i < collection.Count; i++) {
var element = collection.Item(i);
if (element.Name == elementTagName) {
var matches = true;
for (var iVal = 0; iVal < valuesToMatch.length; iVal += 2) {
var property = element.GetPropertyByName(valuesToMatch[iVal]);
var value = property.Value;
if (value != null) {
value = value.toString();
}
if (value != valuesToMatch[iVal + 1]) {
matches = false;
break;
}
}
if (matches) {
return i;
}
}
}
return -1;
}
' Create a Writable Admin Manager object.
Set adminManager = CreateObject("Microsoft.ApplicationHost.WritableAdminManager")
adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST"
' Retrieve the sites collection.
Set sitesSection = adminManager.GetAdminSection("system.applicationHost/sites","MACHINE/WEBROOT/APPHOST")
Set sitesCollection = sitesSection.Collection
' Locate a specific site.
siteElementPos = FindElement(sitesCollection,"site",Array("name","ftp.contoso.com"))
If siteElementPos = -1 Then
WScript.Echo "Element not found!"
WScript.Quit
End If
' Retrieve the site element.
Set siteElement = sitesCollection.Item(siteElementPos)
' Create an object for the ftpServer element.
Set ftpServerElement = siteElement.ChildElements.Item("ftpServer")
' Create an instance of the FlushLog method.
Set FlushLog = ftpServerElement.Methods.Item("FlushLog").CreateInstance()
' Execute the method to flush the logs for the FTP site.
FlushLog.Execute()
' Locate and return the index for a specific element in a collection.
Function FindElement(collection, elementTagName, valuesToMatch)
For i = 0 To CInt(collection.Count) - 1
Set element = collection.Item(i)
If element.Name = elementTagName Then
matches = True
For iVal = 0 To UBound(valuesToMatch) Step 2
Set property = element.GetPropertyByName(valuesToMatch(iVal))
value = property.Value
If Not IsNull(value) Then
value = CStr(value)
End If
If Not value = CStr(valuesToMatch(iVal + 1)) Then
matches = False
Exit For
End If
Next
If matches Then
Exit For
End If
End If
Next
If matches Then
FindElement = i
Else
FindElement = -1 End If
End Function
Hopefully this gives you an idea of how to call the FlushLog method. You can also use these examples to call the Start and Stop methods for FTP sites; you just need to substitute the correct method in place of the FlushLog method.
Cowabunga! The Visual Studio ALM Rangers have published their latest article on www.codeproject.com , which is focused on one of the most exciting dogfooding initiatives we have been involved in … read all about it in How the Visual Studio ALM Rangers use Team Foundation Service to Get Ready for Visual Studio 11.
For .NET 4.5, we’ve invested quite a bit of effort into performance, and in particular for the Task Parallel Library (Joe Hoag wrote a good paper covering some of these improvements). We focused such effort on TPL because it is a core component used in async programming and at a foundational level for many libraries and applications. Small tweaks to the performance characteristics of TPL can thusly have a noticeable impact on the performance of these higher-level systems.
In particular, one of the areas we focused a lot of attention on is memory utilization: how many objects are we allocating, and how big are those objects. This is primarily due to the subsequent costs of garbage collection necessary to clean up those objects… the less we allocate, the less often the GC will need to run and the shorter it will take to run. Sometimes these allocations are clearly visible, in that you see a “new” expression in the code. But often these allocations are hidden.
The Task Parallel Library is written in C#, and C# has some incredibly useful features that help to make programming very productive. The implementation of those features, however, can sometimes result in allocations of which it’s easy to be blissfully unaware. The developers that wrote the C# compiler have done some great work to make the code generated by the compiler efficient, and they’ve implemented a variety of optimizations to help minimize allocations. Still, if you care about eking out the best performance possible and minimizing all possible allocations in the process, it can be very useful to understand the intricacies of the code the compiler generates such that you can bend the behavior better to your will.
In this post, I’ll highlight some of these behaviors we came across during our performance push for TPL, and I’ll demonstrate how you can work around them to help get the best performance possible.
WARNING: Everything I’m discussing in this post is an implementation detail based on one version of the C# compiler (that in .NET 4.5 Developer Preview). It’s certainly possible that these characteristics may change in a future release, as the C# compiler gets more and more optimizations added to it.
Closure and Delegate Allocations
Lambdas and anonymous methods are very powerful features that save the developer from having to write a lot of boilerplate code. Consider the Framework’s ThreadPool.QueueUserWorkItem method:
public static bool ThreadPool(WaitCallback callback);
With lambdas/anonymous methods, I can write code like the following (I’m not recommending this as an approach towards writing to a stream asynchronously, rather just using it as an example of passing state around):
public static void WriteOnPool(Stream stream, byte [] data)
{
ThreadPool.QueueUserWorkItem(delegate
{
stream.Write(data, 0, data.Length);
});
}
Before lambdas/anonymous methods were introduced, C# developers wanting to call a method that accepted a delegate would typically need to define a class to store their state, add a method to that class to do their processing, and then create a delegate that pointed to that method on that state instance, e.g.
public static void WriteOnPool(Stream stream, byte [] data)
{
var state = new WriteOnPoolState();
state.stream = stream;
state.data = data;
ThreadPool.QueueUserWorkItem(new WaitCallback(state.Invoke));
}
private sealed class WriteOnPoolState
{
public Stream stream;
public byte [] data;
public void Invoke(object ignored)
{
stream.Write(data, 0, data.Length);
}
}
Now in C#, when you use an anonymous method or lambda, the compiler actually ends up generating code almost identical to this on your behalf so that you no longer have to do so manually. Here’s a decompiled version of what gets generated for my previous example that used an anonymous method:
public static void WriteOnPool(Stream stream, byte[] data)
{
var locals2 = new DisplayClass1();
locals2.stream = stream;
locals2.data = data;
ThreadPool.QueueUserWorkItem(
new WaitCallback(locals2.<WriteOnPool>b__0));
}
[CompilerGenerated]
private sealed class DisplayClass1
{
public Stream stream;
public byte[] data;
public void <WriteOnPool>b__0(object param0)
{
this.stream.Write(this.data, 0, this.data.Length);
}
}
The important thing to note here is that there are two allocations involved: one for the closure object (in my hand-written version, WriteOnPoolState, and in the compiler-generated version, DisplayClass1), and one for the delegate to the method on the closure. For a method that simply accepts a delegate, there’s really no way around two allocations: the delegate object needs to be allocated, and it needs to target an object containing the state (assuming that state needs to change for each invocation, this state object also needs to be allocated for each call).
Luckily, many library methods that accept delegates recognize the need to pass state into the method, and thus accept not only a delegate object but also a state object that will be passed into the delegate when it’s invoked. In fact, ThreadPool has an additional overload of QueueUserWorkItem that accepts both, and the overload we’ve been using above just passes in null; that’s why the WriteOnPoolState.Invoke and DisplayClass1.<WriteOnPool>b__0 methods both accept an object parameter, so as to match the required signature of a WaitCallback, which accepts an object parameter.
This pattern of accepting an object state is useful because it allows us to avoid allocations. The reason we need to allocate a delegate each time is because its Target needs to point to the right “this” object. But if there is no “this”, i.e. we’re dealing with a static method, then we can reuse the same delegate object over and over, simply passing in different state as a parameter each time. To achieve that, we can rewrite our WriteOnPool example as follows:
public static void WriteOnPool(Stream stream, byte [] data)
{
var state = new WriteOnPoolState();
state.stream = stream;
state.data = data;
ThreadPool.QueueUserWorkItem(s_writeOnPoolBody, state);
}
private static readonly WaitCallback s_writeOnPoolBody =
new WaitCallback(WriteOnPoolBody);
private static void WriteOnPoolBody(object state)
{
var poolState = (WriteOnPoolState)state;
poolState.stream.Write(poolState.data, 0, poolState.data.Length);
}
private sealed class WriteOnPoolState
{
public Stream stream;
public byte [] data;
}
We’re now still allocating a delegate and a state object, but we allocate the delegate only once and cache it into a static field. On each call to WriteOnPool, then, we only allocate once, for the WriteOnPoolState object, saving half of the allocations.
As it turns out, the C# compiler has smarts to provide similar savings when using lambdas and anonymous methods. Let’s say I instead rewrite my implementation as follows, still using a lambda, but now passing in my state via the object state parameter and ensuring that my lambda doesn’t close over anything (I’m also using a Tuple<,> for conciseness to avoid needing to define my own custom state type):
public static void WriteOnPool(Stream stream, byte[] data)
{
ThreadPool.QueueUserWorkItem(state =>
{
var poolState = (Tuple<Stream,byte[]>)state;
poolState.Item1.Write(
poolState.Item2, 0, poolState.Item2.Length);
}, Tuple.Create(stream, data));
}
This now results in the following code from the compiler:
public static void WriteOnPool(Stream stream, byte[] data)
{
if (CachedAnonymousMethodDelegate1 == null)
CachedAnonymousMethodDelegate1 =
new WaitCallback(Program.<WriteOnPool>b__0);
ThreadPool.QueueUserWorkItem(
CachedAnonymousMethodDelegate1,
Tuple.Create<Stream, byte[]>(stream, data));
}
[CompilerGenerated]
private static WaitCallback CachedAnonymousMethodDelegate1;
[CompilerGenerated]
private static void <WriteOnPool>b__0(object state)
{
Tuple<Stream, byte[]> poolState = (Tuple<Stream, byte[]>) state;
poolState.Item1.Write(poolState.Item2, 0, poolState.Item2.Length);
}
Note that the compiler has done something very similar to what we did manually, creating a static field to cache the delegate. The primary difference between what we manually wrote and what the compiler generated is the compiler is lazily instantiating the delegate on first use, rather than doing it in the static constructor as we did by using a field initializer. So, we get to have our cake and eat most of it, too… we still get most of the convenience of lambdas while getting the efficiency benefits of the delegate caching. And, of course, if the state I’m trying to pass in is already a single object, that object can be passed in directly (rather than wrapping it in a state object), bringing us down to zero additional allocations.
When Automatic Caching Fails
This is all well and good, but it can lead us into a fall sense of security, as there are times when the compiler will not cache the delegate.
One prime example is that the compiler won’t cache the delegate when a method group is used rather than a lambda / anonymous method, e.g.
public void WriteOnPool(Stream stream, byte[] data)
{
ThreadPool.QueueUserWorkItem(
WriteOnPoolCallback,
Tuple.Create(stream, data));
}
private static void WriteOnPoolCallback(object state)
{
var poolState = (Tuple<Stream, byte[]>)state;
poolState.Item1.Write(
poolState.Item2, 0, poolState.Item2.Length);
}
Some developers prefer the explicitness of having a named method, but the compiler currently generates code like the following for this:
public void WriteOnPool(Stream stream, byte[] data)
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(Program.WriteOnPoolCallback),
Tuple.Create<Stream, byte[]>(stream, data));
}
private static void WriteOnPoolCallback(object state)
{
Tuple<Stream, byte[]> poolState = (Tuple<Stream, byte[]>) state;
poolState.Item1.Write(
poolState.Item2, 0, poolState.Item2.Length);
}
Notice the delegate allocation on each call. In such a situation, you might prefer to do the caching manually, or to revert to using a lambda or anonymous method.
Another example where the compiler won’t cache is when dealing with certain patterns of generics usage. Consider the following variation. Here rather than writing a byte[] to the stream, I’m using a BinaryFormatter to serialize an arbitrary generic T to the stream:
public void WriteOnPool<T>(Stream stream, T data)
{
ThreadPool.QueueUserWorkItem(state =>
{
var poolState = (Tuple<Stream, T>)state;
new BinaryFormatter().Serialize(
poolState.Item1, poolState.Item2);
}, Tuple.Create(stream, data));
}
The compiler will currently not cache a delegate for this case, instead generating code like the following:
public void WriteOnPool<T>(Stream stream, T data)
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(Program.<WriteOnPool>b__0<T>),
Tuple.Create<Stream, T>(stream, data));
}
[CompilerGenerated]
private static void <WriteOnPool>b__0<T>(object state)
{
Tuple<Stream, T> poolState = (Tuple<Stream, T>) state;
new BinaryFormatter().Serialize(
poolState.Item1, poolState.Item2);
}
A little thought reveals why the compiler doesn’t use the same caching pattern it does elsewhere. Notice that the method generated for the lambda is a generic method, and for it to be cached, it would need to be cached in a static field for each T that might exist… that’s not possible in a field on a class that’s not parameterized on the same generic type parameter. We can manually work around this by caching the delegate manually: we just need to create a generic type to contain the field:
public void WriteOnPool<T>(Stream stream, T data)
{
ThreadPool.QueueUserWorkItem(
DelegateCache<T>.s_writeOnPoolCallback,
Tuple.Create(stream, data));
}
private static class DelegateCache<T>
{
internal static readonly WaitCallback s_writeOnPoolCallback =
state =>
{
var poolState = (Tuple<Stream, T>)state;
new BinaryFormatter().Serialize(
poolState.Item1, poolState.Item2);
};
}
Theoretically, the compiler could perform a similar transformation, for example creating one such generic cache per assembly and per generic arity, but it currently does not do so.
Another common case where such lack-of-caching goes unnoticed is when dealing with instance methods and data. Consider the following similar code:
internal class MyCoolType
{
private Stream m_stream;
private byte[] m_data;
public void WriteOnPool()
{
ThreadPool.QueueUserWorkItem(delegate
{
m_stream.Write(m_data, 0, m_data.Length);
});
}
}
This example will generate code like the following:
internal class MyCoolType
{
private Stream m_stream;
private byte[] m_data;
public void WriteOnPool()
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(this.<WriteOnPool>b__0));
}
[CompilerGenerated]
private void <WriteOnPool>b__0(object param0)
{
this.m_stream.Write(this.m_data, 0, this.m_data.Length);
}
}
The anonymous method refers implicitly to ‘this’, closing over member fields of the current instance. As such, the compiler generates an instance method for that anonymous method, and then because it needs a delegate instance with a Target set to this particular instance, each call to WriteOnPool will end up allocating a new delegate (it would be possible for the compiler to have added an instance field in order to cache this delegate, but that could have negative consequences, such as making each instance of this class bigger, and the compiler can’t easily reason about the global impacts of such caching). Of course, we have knowledge that the compiler doesn’t have: we know that we can use the object state parameter in order to pass data into the method. So, we could instead write our code as:
internal class MyCoolType
{
private Stream m_stream;
private byte[] m_data;
public void WriteOnPool()
{
ThreadPool.QueueUserWorkItem(state =>
{
MyCoolType mct = (MyCoolType)state;
mct.m_stream.Write(mct.m_data, 0, mct.m_data.Length);
}, this);
}
}
or as:
internal class MyCoolType
{
private Stream m_stream;
private byte[] m_data;
public void WriteOnPool()
{
ThreadPool.QueueUserWorkItem(
state => ((MyCoolType)state).Write(), this);
}
private void Write()
{
m_stream.Write(m_data, 0, m_data.Length);
}
}
and in both cases, we’ll get the caching we expect. This is an example of the case I referred to earlier, where we already have a single state object to pass in, and thus we don’t need to allocate a wrapper (e.g. a tuple), which means there are no additional allocations here.
Closures and Fast Paths
There are other times when the compiler isn’t yet quite as clever as we might expect it to be. One case in which this comes up is when using “fast paths” to optimize frequented code paths. Consider a change to our WriteOnPool method: the goal of the method isn’t to queue a work item to do the write, but rather to ensure the write happens on a ThreadPool thread; as such, if we’re already on a ThreadPool thread, we can avoid the queueing operation:
public static void WriteOnPool(Stream stream, byte[] data)
{
if (Thread.CurrentThread.IsThreadPoolThread)
{
stream.Write(data, 0, data.Length);
}
else
{
ThreadPool.QueueUserWorkItem(delegate
{
stream.Write(data, 0, data.Length);
});
}
}
I might then expect that my “fast path” that occurs when I’m already on a ThreadPool thread won’t involve any additional allocations for the closure/delegate used on the “slow path.” But such an expectation is based on an assumption that the compiler allocates the closure in the “else” block. In fact, the compiler currently generates code like the following:
public static void WriteOnPool(Stream stream, byte[] data)
{
var locals3 = new DisplayClass2();
locals3.stream = stream;
locals3.data = data;
if (Thread.CurrentThread.IsThreadPoolThread)
{
locals3.stream.Write(locals3.data, 0, locals3.data.Length);
}
else
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(locals3.<WriteOnPool>b__0));
}
}
[CompilerGenerated]
private sealed class DisplayClass2
{
public byte[] data;
public Stream stream;
public void <WriteOnPool>b__0(object param0)
{
this.stream.Write(this.data, 0, this.data.Length);
}
}
Note that the “locals” that are captured into the closure actually live on the heap-allocated closure object and are accessed there, even from code paths that don’t use the closure. Thus, the closure object gets allocated at the beginning of the method. This means that we’re still paying for the closure object even if we only take the “fast path” that doesn’t actually require it. If we instead separate out the closure into a separate method, we can eliminate that allocation from the fast path, e.g.
public static void WriteOnPool(Stream stream, byte[] data)
{
if (Thread.CurrentThread.IsThreadPoolThread)
{
stream.Write(data, 0, data.Length);
}
else WriteOnPoolPrivate(stream, data);
}
private static void WriteOnPoolPrivate(Stream stream, byte[] data)
{
ThreadPool.QueueUserWorkItem(delegate
{
stream.Write(data, 0, data.Length);
});
}
Moral of the Story
C# and Visual Basic provide some very powerful language features for you to use, and they typically do a very good job of implementing what’s under the hood. But if your particular scenario demands pedal-to-the-medal performance, you need to at least understand what’s happening on your behalf so that you can better influence it as necessary. Get friendly with tools like .NET Reflector that help you to see what’s actually going on in the compiled code.
If you do use a decompiler for this kind of analysis, be certain that it’s not sweeping such details under the rug for you. A primary use of these decompilers is to get high-quality source generated from low-level IL, and thus decompilers will often attempt to decompile back to source that employs anonymous methods and lambdas and the like. If instead your goal is to get a closer view on what’s actually happening, try tweaking the settings of the decompiler to minimize what language features it reverse engineers to, e.g. in .NET Reflector, you can change the “optimization level” so that it shows you code like what I’ve shown in this post, rather than hiding these allocations behind a lambda.
One last thought. Throughout this post, I kept harping on the number of allocations, but I didn’t spend much time on the size of the allocations. The number of allocations is only one aspect to consider. We also want to consider the amount of memory being allocated, as that will factor into how often the garbage collector runs. There are lots of tools to help determine the amount of memory .NET applications are allocating, but when prototyping I often find myself using a function like the following to give me a rough sense for what something is costing:
public static class MemoryAnalysis
{
public static long AveragedApproximateSize<T>(Func<T> rootGenerator) where T : class
{
const int iters = 1000000;
var items = new object[iters];
long start = GC.GetTotalMemory(true);
for (int i = 0; i < items.Length; i++)
items[i] = rootGenerator();
long end = GC.GetTotalMemory(true);
GC.KeepAlive(items);
return (long)Math.Round((end - start) / (double)iters);
}
}
When I then run:
static void Main()
{
Console.WriteLine(MemoryAnalysis.AveragedApproximateSize(
() => new WriteOnPoolState()));
Console.WriteLine(MemoryAnalysis.AveragedApproximateSize(
() => new WaitCallback(WriteOnPoolBody)));
}
I see that WriteOnPoolState is 16 bytes and WaitCallback is 32 bytes (in a 32-bit compilation), which makes logical sense if you add up the size of the fields on the objects plus the object headers. That means that for the examples where we were able to eliminate the delegate allocation by caching the delegate in a static, we were not only saving half the number of allocations, but we were also saving 2/3rds of the memory being allocated.
Happy optimizing.
Periodically, I’ll post a non-work related blog leaning toward more personal observations. I hope you still enjoy the read. ![]()
First off, yes, I know the building blocks of life are more biological in nature (cells, genes, etc.). But, in this post I’m focusing on the building of knowledge and awareness through hands on learning.
Second, I’m a huge Lego fan! One of my childhood passions has been totally revised by having two young daughters. If you doubt me, here’s an excerpt from a letter my parents received almost 30 years ago…
Thank you for your nice letter and for sending the newspaper article and photographs relating to your son, Kevin’s, “Transformer” creations. We are glad to hear that Kevin enjoys building with LEGO® products. He certainly seems to have very creative and innovative talent with the models he has made….We will be happy to post the newspaper article and photographs our Company bulletin board for our employees and visitors to enjoy and admire.
Now, as a youngster, I was completely amazed to receive this letter (plus they threw in a gift right before my birthday too!), but looking back, it’s great to see how this remarkable response has really stuck with me over the years. In the pre-internet information age, there was no such thing as an instant response. Someone carved out a little time in their busy day to personally mail a note back.
Finally, circling back to building knowledge and awareness, I’m really excited to see this year Lego introduced a line of products specifically targeted at girls – LEGO® Friends. I’m all for Star Wars, Harry Potter, etc. but right now I’m pretty sure my “dolls rule the world” daughters will be really excited to play with these. I can hardly wait to see their imaginations run wild. Easily hours of enjoyment for the whole family!
--Kevin
I love the Actions feature in OData – which is hardly surprising given I was one of its designers.
Here’s the main reason why I love it: Actions allow you move from a CRUD architecture style, where you query and modify data using the same model, to an architectural style where you have a clear separation between the model used to query and the model used to update. To me this feels a lot like Greg Young’s baby CQRS, or Command Query Responsibility Segregation.
I’ll admit I’m taking some liberties here because these two models are actually ‘merged’ into a single metadata document ($metadata) that describes them both, and you can share types between these two models… however this feels insignificant because the key benefits remain.
Why would you want to move from a CRUD style application to a CQRS style one?
Let’s look at a simple scenario, imagine you have Products that look like this:
public class Product
{
public int ID {get;set;}
public string Name {get;set;}
public Decimal Cost {get;set;}
public Decimal Price {get;set;}
}
And imagine you want to Discount Marmite (a product in your catalog) by 15%. Today using the CRUD style, the default in OData before Actions, there is only one option: you PUT a new version of the Marmite resource with the new Price to the URL that represents Marmite, i.e. something like this:
POST ~/Products(15) HTTP/1.1
Content-Type: application/json
{
// abbreviated for readability
“ID”: 15,
“Name”: “Marmite”,
“Cost”: 3.50,
“Price”: 4.25 // ($5 – 15%)
}
Notice to support this you have to allow PUT for Products. And this has some real issues:
More generally the CRUD model is painful because:
Back to our scenario, it would be much better to disable PUT completely and create a Discount action, and advertise it’s availability in the Marmite resource (to keep your system as Hypermedia driven as possible):
{
“__metadata”: {
// abbreviated for simplicity
“Actions”: {
“#MyActions.Discount”: [{ “title”: “Discount Marmite”, “target”: “Products(15)/Discount”}]
}
},
“ID”: 15,
“Name”: “Marmite”,
“Cost”: 3.50,
“Price”: 5.00
}
The name of the Action (i.e. #MyActions.Discount) is an ‘anchor’ into the metadata document that can be found at ~/$metadata that says you need to provide a percentage.
POST ~/Products(15)/Discount HTTP/1.1
Content-Type: application/json
{
“percentage”: 15
}
This is much better. Notice this doesn’t allow me to modify the Cost or the Name, and indeed can easily be validated to make sure the percentage is within an acceptable range, and it is semantically much clearer what is happening.
In fact by moving from a CRUD style architecture to one inspired by CQRS but based on actions you can:
Of course simply separating the read/write models in OData doesn’t give you all of these advantages immediately, but at least it creates a foundation that can scale to support things like Event Sourcing or Eventual Consistency later if required.
Some of you may be thinking you can achieve many of these goals by having a more granular model that makes things like “Discount” a resource, and that would be true. However for most people using OData that way of thinking is foreign and more importantly the EDM foundations of OData get in the way a little too. So for me Actions seems like the right approach in OData.
I love this.
But what do you think?
-Alex
This is a guest video post by Pankaj Arora, senior manager in the Global Strategic Initiatives team, Microsoft IT. See his prior post about the new book, “To the Cloud: Cloud Powering an Enterprise.”
Once you have envisioned the ways your organization can benefit from using cloud computing, the next step is to decide how exactly to move forward.
In the video below, I sit down with co-author Salil Dave to talk about important considerations and practices to enable cloud computing in an enterprise. Our discussion draws on our experiences within Microsoft IT, and experiences from the many enterprise customers we’ve met. In the video we touch on different topics including approaches to cloud adoption, selecting a service provider, investing in training, and cloud governance.
At the end of the video we also discuss the DevOps model, in which there is tighter integration between development and operations. In DevOps, there is often more fluid communication and more frequent releases. Software developers understand operational patterns and practices well, and operations personnel have a greater understanding of the technologies programmers use to build services. This model is important for IT shops to digest to maximize the benefits of the cloud. I’ve also included a short excerpt from the book below regarding DevOps, and of course there are many more best practices covered in the book.
Web 2.0 companies like Netflix and Flickr have written about their experiences using the DevOps model. In a presentation given at Velocity 2009 entitled “10+ Deploys per Day: Dev and Ops Cooperation at Flickr,” John Allspaw and Paul Hammond described how Flickr teams applied DevOps concepts to roll out as many as ten deployments in a day. They automated the deployment of infrastructure, created a one-step build and deploy process for shipping releases, and used online collaboration to coordinate issue resolution during releases.
Adrian Cockcroft’s April 2011 presentation about how Netflix did a full migration of its website to public cloud services, entitled “Moving Your Organization to Public Cloud,” drew many of the same conclusions about DevOps as Allspaw and Hammond did. Developers remain the owners of code running in production environments. Operations work shifts to writing code and creating tools that automate processes. Both roles have a part to play in collecting metrics. A flatter and more collaborative IT organization is necessary to accomplish all of this.
Most enterprise IT groups already have release management processes in place. DevOps can reduce development cycles from weeks or months to days or weeks, which means project managers or release coordinators will see a corresponding shift in their duties. Releasing smaller components more often lessens the risk of failures, assuming rollbacks are easy.
We suggest you take a close look at agile software development methodologies, such as Scrum, if you have not already done so. Also consider changing job descriptions or performance review goals to encourage better collaboration among IT staff. For example, educational goals could include “Operations engineers demonstrate a working knowledge of detailed systems design,” or “Software developers work one shift to support applications they built (per week, month, or quarter).”
View Video
Format: mp4
Duration: 4 minutes
Blog : How to create multiple listeners for the same availability group
As the PM who designed the availability group listener feature, when I talked to some customers , there’re 2 scenarios I realized may need to have multiple listeners for a single availability group.
Scenario 1:
This Customer has a few legacy clients and he cannot change the connection string for them. Plus, these legacy clients used to use 3 different instance names to connect to database. Now since they want to leverage AlwaysOn Availability Group Listener, without changing all legacy client connection string, they can only 1 kind of 3 client work if they switch to AlwaysOn.
We thought though 2 possible solutions: CNAME vs. Multiple listeners – the latter one is kind of my favorite secret J since from SQL you can only create 1 listener per availability group.
We compared 2 solutions below and they finally go with multiple listeners
|
|
Pros |
Cons |
|
Multiple Availability Group listeners |
|
|
|
DNS (CNAME) |
|
|
Scenario 2:
There’s another customer told me he uses NUMA system with SQL. The interesting thing he does with SQL is to make SQL listen to multiple ports and system allocates different resources to the client based on the port it connects to. (That’s barely what I learned from him)
So he also wants to configure a few more listeners when availability group comes to the picture so his original logic can still work.
How to configure
1> Setup AlwaysOn Availability Group (agsc4), skip listener creation in the wizard or T-SQL
2> Go to cluster manager , create “client access point”, you can create multiple of them. (There’s a quota limitation of how many computer objects you may create in one cluster – I think it’s 20 by default)
3> It looks like the picture below, I created 3 listeners and assigned IPs for each of them.
We recommend you use “OR” dependencies for IPs in each listener but you can use “AND” if required. (e.g. you want a IPv4 and a IPv6 both online to make the listener online)
4> Make sure all listeners you want to create are online and associate them with your availability group resource – make sure you use “OR” in dependencies – this means as long as one listener is online your availability group is considered online and available to your clients.
5> Now if you query: sys.availability_group_listeners – you should be able to see all of them.
Note: you can see all the ports are “NULL”.
6> Now, you still cannot use these listeners. You need to go back to run T-SQL to assign port for each of them.
I use 1433 (the default SQL listening port) for all of 3, you can definitely assign different port to them (as Scenario 2 described)
alter availability group [agsc4]
modify listener 'agsc4_listener1'
(port = 1433)
alter availability group [agsc4]
modify listener 'agsc4_listener2'
(port = 1433)
alter availability group [agsc4]
modify listener 'agsc4_listener3'
(port = 1433)
7> Query sys.availability_group_listeners again, you should be able to see they all have ports and SQL is listening to them.
8> Now connecting to any of the listeners you created, it should bring you to the same instance which host the availability group primary replica:
Difference between listener created through SQL and created in Cluster Manager
if you recall, in SQL Server 2012 CTP0/CTP1, we still don’t have integrated manageability or T-SQL experience for our customers to create AG Listener inside SQL. After CTP1, we provided this integrated user flow in SQL. But you can still create listener through Cluster Manager.
So what’s the difference and in which scenario you want to do this?
Here’s a comparison between listeners created through SQL and created in cluster manager:
|
|
Listener Created by SQL |
Listener Created in Windows Failover Cluster Manager |
|
Can use immediately? |
Yes |
No. You must run T-SQL to assign the port to the listener before you can use it. |
|
IP relation inside listener |
Only “OR” for all IPs inside listener |
You can customize “OR” or “AND” for IPs inside listener to meet your custom need. (e.g. you want to have one IPv4 and one IPv6 both online to make the listener online)
|
|
Yes SQL set this private property to 1 (or true) to make sure DNS registers all IPs inside the listener.
This is to ensure should a failover happen, your client doesn’t need to resolve the new IPs from another subnet (if it’s in multisubnet scenario).
|
No If you want to get the benefits as stated in the left column – you need to run powershell script to enable this by yourself. |
|
|
Can be managed through SQL |
Yes You can drop , add IP and change port of the listener |
Depends You need to check “is_conformant” value of the listeners you created outside of SQL in sys.availability_group_listeners
This property will tell you if you can manage it through SQL or not.
If it’s not conformant, the only thing you can do through T-SQL is to change the port. You cannot drop it or add IPs – these need to be done through Failover Cluster Manager.
|
Last but not least, please use sys.dm_tcp_listener_states to check real time listener connection and status – this dmv is very helpful to trouble shoot your connectivity related issues and we newly introduced it in SQL Server 2012.
Goden Yao, Program Manager
SQL Server Engine High Availability
If you worked with federations, I am sure you are already know about the online tools like SQL Azure Management portal that give you the ability to orchestrate your federations with repartitioning operations or resize member MAXSIZE and edition.
In episode #69 on Cloud Cover, George and Wade cover moving schema and data between SQL Server, SQL Azure databases with Federations! So you can move SQL Server databases to SQL Azure Federation, or single scale-up SQL Azure databases to SQL Azure Federations or simply transfer, move data between SQL Azure Federations. All these are possible with the well known community tool : SQL Azure Migration Wizard. What is great is the code is available on codeplex and the tool generates the scripts you can run from command line for you. You don’t get the great retry logic or the parallelism with that SQL Azure Migration Wizard provides when you do that however…
There is one more good news in all this; George does not cover this in his talk but, you can also use SQL Azure Migration Wizard to perform the missing MERGE repartitioning operation manually. There is an article that is coming on that topic soon. You simply export a member, then DROP the existing member that has been exported. Then import the data back in. Fantastic!
Well here is the episode; watch if for yourself;
-cihan
In this Visual Studio magazine article, my colleague Max Zilberman shares top 10 tips for developers to build Windows Phone apps in a right way.
Read the full article here.
To get started, developers can download free tools including Windows Phone SDK.
In this Visual Studio magazine article, my colleague Max Zilberman shares top 10 tips for developers to build Windows Phone apps in a right way.
Read the full article here.
To get started, developers can download free tools including Windows Phone SDK.
Some Free February Appy-ness with a new piece of free software for teachers from Microsoft every day in February. Many of these items are unknown heroes, but they all share two things in common: 1) They are useful for teachers or students and 2) they are free.
So you’ve got a handful of digital cameras. And every student wants to take a photo. How about finding a way to get the students’ work to build up into one big image, rather than lots of individual snaps.
What can it do?
HD View is an image viewer that was created by Microsoft Research, which allows you to display and interact with very large images (the kind of images that have billions of pixels). And you can create these images yourself, and then publish them on the web so that everybody can pan and zoom around them.
If you want to get an idea of what’s possible, take a look at the Harlem HD View (it will prompt you to install the viewer in your browser) or some of the European HD View photography from Bernhard Vogl
http://research.microsoft.com/en-us/um/redmond/groups/ivm/HDView/HDabout.htm
How would I use it?
The kind of examples where HD View comes in handy are:
- You want to upload a high resolution image from a camera, and make it easy to view
eg you have a 10 megapixel camera, and don’t want to just upload a small version of an image - eg to publish a high resolution photo or scan of a student’s artwork- You want to make a super-high resolution panorama
eg you create landscape panoramas for geography lessons, using programmes like Windows Live Photo Gallery or Microsoft Image Composite Editor, where you want to be able to go from a wide angle view, right down to looking at individual geographic features in the rocks.- You want to put lots of different images together into a single image
eg you have a panorama of your school art show, and you want to give people the ability to zoom right in; or your students create a timeline that you want to be able to zoom in and out of
In addition to the ‘Create your own HD View Content’ page on the HD View website, there are also so great tips on the HD View blog (like how to create the amazing panorama below from a video and a series of tutorials for the Image Composite Editor)

HD View itself is a plug-in for your web browser, which gets downloaded when people go to look at the content you create. What you do need to get are the tools you create the HD View images in - all the options, including the Photoshop add-in, are here
Visual Studio on Facebook | Follow @VisualStudio on Twitter | Learn more about Visual Studio | Learn more about Visual Studio Testing Tools | Visual SourceSafe Upgrade
1478
In this post, I’ll give examples of PowerShell scripts for configuring your SQL server instances for AlwaysOn.
Before continuing, please review the system requirements for AlwaysOn Availability Groups: Prerequisites, Restrictions, and Recommendations for AlwaysOn Availability Groups (SQL Server)
A note on running scripts: To run the script samples below, copy the samples into a local file on one of your domain-joined servers (ensure the file has the *.ps1 extension). Then open a PowerShell console and launch SQLPS, the SQL PowerShell scripting environment, by typing “SQLPS”. Note that you need to have SQL Server Management tools installed to run SQLPS. Next, ensure that your execution policy is set to Unrestricted. Since SQLPS has an execution policy separate from the system execution policy, you have to specify the -Scope parameter, as follows:
Set-ExecutionPolicy Unrestricted -Scope Process
Then, you can run the script from the local file. For example, if I copy a script to C:\scripts\temp.ps1, my session would look like:
PS C:\> SQLPS
Microsoft SQL Server PowerShell
Version 11.0.2100.54
Microsoft Corp. All rights reserved.
PS SQLSERVER:\> Set-ExecutionPolicy Unrestricted -Scope Process
PS SQLSERVER:\> C:\scripts\temp.ps1
All machines that host server instances in your AlwaysOn Availability Groups configuration must be members of a Windows Failover Cluster. I’ll give a brief overview of how to create a cluster, in case you do not already have one. First, ensure that the Windows Server Failover Clustering feature is enabled on all your servers. You can do so through the server manager UI, see Install the Failover Clustering Feature, or you can use the following PowerShell commands from an elevated PowerShell prompt (in Windows Server 2008 R2 only):
Import-Module ServerManager
Add-WindowsFeature Failover-Clustering
Run this command on every machine that you wish to join to the cluster. Next you have to create the actual cluster. Again, you can either user the server manager (see Create a New Failover Cluster in Server Manager) or PowerShell commands (see Using Windows PowerShell Cmdlets on Failover Clusters in Windows Server 2008 R2). If you wish to use PowerShell, take a look at the Test-Cluster and New-Cluster cmdlets. The former is used to run the Windows Clustering verification tests on your machines, a prerequisite for creating a cluster. The latter is used to create the cluster.
Once you have created the failover cluster, you need to enable the AlwaysOn feature and create endpoints on all of your instances of SQL Server. These endpoints facilitate the movement of data between servers. Happily, we can do this entire configuration in PowerShell, as demonstrated in the script below.
###########################################################
# SCRIPT VARIABLES
# Set these values before running the script!
###########################################################
# Name of the server instances that will participate in the availability group
$ServerList = @("mymachine\myinstance", "myothermachine\myotherinstance")
# The default port used by the endpoints, if we need to create them
$EndpointPort = 5022
# The name of the endpoint created on each server, if we need to create one
$EndpointName = "AlwaysOn_Endpoint"
###########################################################
# SCRIPT BODY
###########################################################
foreach ($server in $ServerList)
{
# Connection to the server instance, using Windows authentication
Write-Host -Foreground Green "Creating SMO Server object for server: $server"
$serverObject = New-Object Microsoft.SQLServer.Management.SMO.Server($server)
# Enable AlwaysOn. We use the -Force option to force a server restart without confirmation.
# This WILL result in your SQL Server instance restarting.
Write-Host -Foreground Green "Enabling AlwaysOn on server instance: $server"
Enable-SqlAlwaysOn -InputObject $serverObject -Force
# Check if the server already has a mirroring endpoint
$endpointObject = $serverObject.Endpoints `
| Where-Object { $_.EndpointType -eq "DatabaseMirroring" } `
| Select-Object -First 1
# Create an endpoint if one doesn't exist
if($endpointObject -eq $null)
{
Write-Host -Foreground Green "Creating endpoint on server instance: $server"
$endpointObject = New-SqlHadrEndpoint `
-InputObject $serverObject `
-Name $EndpointName `
-Port $EndpointPort
}
else
{
Write-Host -Foreground Yellow "An endpoint already exists on '$server'."
}
# Start the endpoint
Write-Host -Foreground Green "Starting endpoint on server instance: $server"
Set-SqlHadrEndpoint -InputObject $endpointObject -State "Started" | Out-Null
}
Let’s walk through this script. At the top, are a few variables that you should set based on your local environment. The ServerList variable holds the names of the servers we wish to configure. The EndpointPort variable holds the port number we assign by default to the endpoints we create. The EndpointName variable holds the name we assign by default to the endpoints we create.
In the body of the script, we iterate through the server list, and perform the following for each entry: first, we connect to the instance using Windows authentication (therefore, the user running this script is assumed to have sufficient privileges on each server instance). Next, we enable the AlwaysOn feature using the Enable-SqlAlwaysOn cmdlet. It’s important to note the -Force parameter we provide to this cmdlet: enabling AlwaysOn requires a restart of the SQL Server service, and the -Force option tells the cmdlet to go ahead and perform this restart without user confirmation. Without this parameter, the script will pause and ask you to confirm the restart. Next, we check if a database mirroring endpoint exists on the server. If not, we create an endpoint using the New-SqlHadrEndpoint cmdlet. Finally, we use the Set-SqlHadrEndpoint cmdlet to set the state of the endpoint to “Started”.
Some important notes about endpoints: In the example above, we assume that (1) the SQL Server service account on each server instance is a domain account, and (2) the same domain account is used for all service accounts. If this is not the case in your environment, you will have to grant the CONNECT permission on the endpoints created by this script to all of your service accounts. There is no explicit cmdlet support for this operation, but you can still script this step using the SQL Server Management Objects API (see the following API reference: Endpoint.Grant Method). Otherwise, you can always use the Invoke-Sqlcmd cmdlet to directly execute Transact-SQL statements.
Now we can, at last, create our availability group. There are several steps to this process, all of which are supported by PowerShell cmdlets:
Here is a script demonstrating these steps:
###########################################################
# SCRIPT VARIABLES
# Set these values before running the script!
###########################################################
# Name of the server instances that will participate in the availability group.
# The first server is assumed to be the initial primary, the others initial secondaries.
$ServerList = @("mymachine\myinstance", "myothermachine\myotherinstance")
# Name of the availability group
$AgName = "MyAvailabilityGroup"
# Names of the databases to add to availability group
$DatabaseList = @("mydatabase")
# Directory for backup files
$BackupShare = "\\my\backup\share"
###########################################################
# SCRIPT BODY
###########################################################
# Initialize some collections
$serverObjects = @()
$replicas = @()
foreach ($server in $ServerList)
{
# Connection to the server instance, using Windows authentication
Write-Host -Foreground Green "Creating SMO Server object for server: $server"
$serverObject = New-Object Microsoft.SQLServer.Management.SMO.Server($server)
$serverObjects += $serverObject
# Get the mirroring endpoint on the server
$endpointObject = $serverObject.Endpoints `
| Where-Object { $_.EndpointType -eq "DatabaseMirroring" } `
| Select-Object -First 1
# Create an endpoint if one doesn't exist
if($endpointObject -eq $null)
{
throw "No Mirroring endpoint found on server: $server"
}
$fqdn = $serverObject.Information.FullyQualifiedNetName
$port = $endpointObject.Protocol.Tcp.ListenerPort
$endpointURL = "TCP://${fqdn}:${port}"
# Create an availability replica for this server instance.
$replicas += (New-SqlAvailabilityReplica `
-Name $server `
-EndpointUrl $endpointURL `
-AvailabilityMode "AsynchronousCommit" `
-FailoverMode "Manual" `
-AsTemplate `
-Version 11)
}
$primary, $secondaries = $serverObjects
# Create the initial copies of the databases on the secondaries,
# via backup/restore
foreach ($db in $DatabaseList)
{
$bakFile = Join-Path $BackupShare "$db.bak"
$trnFile = Join-Path $BackupShare "$db.trn"
Write-Host -Foreground Green "Backing up database '$db' on $primary to $bakFile"
Backup-SqlDatabase `
-InputObject $primary `
-Database $db `
-BackupFile $bakFile `
-Init
Write-Host -Foreground Green "Backing up the log of '$db' on $primary to $trnFile"
Backup-SqlDatabase `
-InputObject $primary `
-Database $db `
-BackupFile $trnFile `
-BackupAction "Log" `
-Init
foreach($secondary in $secondaries)
{
Write-Host -Foreground Green "Restoring database '$db' on $secondary from $bakFile"
Restore-SqlDatabase `
-InputObject $secondary `
-Database $db `
-BackupFile $bakFile `
-NoRecovery
Write-Host -Foreground Green "Restoring the log of '$db' on $secondary from $trnFile"
Restore-SqlDatabase `
-InputObject $secondary `
-Database $db `
-BackupFile $trnFile `
-RestoreAction "Log" `
-NoRecovery
}
}
# Create the availability group
New-SqlAvailabilityGroup `
-Name $AgName `
-InputObject $primary `
-AvailabilityReplica $Replicas `
-Database $DatabaseList
# Join the secondary replicas, and join the databases on those replicas
foreach ($secondary in $secondaries)
{
Write-Host -Foreground Green "Joining instance '$secondary' to the AG '$AgName'"
Join-SqlAvailabilityGroup -InputObject $secondary -Name $AgName
$ag = $secondary.AvailabilityGroups[$AgName]
Write-Host -Foreground Green "Joining databases on '$secondary' to the AG '$AgName'"
Add-SqlAvailabilityDatabase -InputObject $ag -Database $DatabaseList
}
As before, the script begins with a few variables that you should define based on your environment. ServerList is the same as before, however the ordering is relevant. We assume that the first element of the list is the server instance that will host the initial primary replica, where all of the databases are stored. The AgName variable holds the name of the availability group we will create. DatabaseList holds the names of the databases on the initial primary replica that we want to include in our availability group. Lastly, BackupShare is the file system location where we shall store the backups done as part of the “seeding” operation.
In the script body, we again iterate through the server list and establish connections. Then, for each server, we create an Availability Replica object, using the New-SqlAvailabilityReplica cmdlet. We pass the various replica configuration options, such as the failover mode and availability mode, to this cmdlet. We specify the -AsTemplate parameter here, which creates the availability replica object in memory (as opposed to committing the change on the server, an impossibility since we haven’t created the availability group yet). The -Version parameter indicates the server version for which we should create this in-memory object (this should match the version of the server where you ultimately create the availability group). We access the endpoint on the server to generate an endpoint URL for the replica (explained here). Next, we perform the data seeding step. We back up each database and its log, using the Backup-SqlDatabase cmdlet. Then we restore the database and log to each secondary, using the Restore-SqlDatabase cmdlet. Crucially, we use the -NoRecovery option when performing the restores, a requirement for AlwaysOn.
Next, we create the availability group with the New-SqlAvailabilityGroup cmdlet. We pass in the in-memory replica configurations that we created above, as well as the list of database names. Finally, we iterate through all the secondary replicas, joining them to the availability group with the Join-SqlAvailabilityGroup cmdlet and joining the secondary databases therein with the Add-SqlAvailabilityDatabase cmdlet.
По мере приближения к следующему общедоступному контрольному этапу мы будем возвращаться к темам, описанным в этом блоге, и поговорим об изменениях в продукте, внесенных после выхода предварительной версии для разработчиков. Как мы часто говорим, мы читаем комментарии, обсуждения и отзывы о Windows 8 и тщательно отслеживаем все мнения. Мы прислушиваемся к этим отзывам, учитывая их источник и влияние на целевую аудиторию, а также пытаемся разобраться с конфликтующими отзывами (независимо от того, сколько людей проголосовало за, мы можем обещать, что для любых стоящих обсуждения возможностей существуют конфликтующие и настолько же ценные точки зрения.) Конечно, мы всегда рассматриваем возможность реализации любых изменений — совместимость, безопасность, производительность и т. д.
Автор этой стати — Илана Смит (Ilana Smith), ведущий руководитель программы в группе технических систем.
--Стивен
Ранее мы опубликовали три записи, в которых обсуждались новые возможности управления файлами в Windows 8: одна о новых функциях копирования, другая с подробным описанием процесса разработки новой обработки конфликтов и еще одна запись об изменениях проводника Windows, в том числе включении в него ленты.
Эти записи вызвали волну обсуждений и мы прочитали около 2200 комментариев. Это были очень полезные для нас отзывы, и мы использовали их в процессе разработки вместе с информацией из других каналов.

Обобщение комментариев к записям блога
Когда мы готовились к выходу бета-версии, мы хотели осветить некоторые ключевые вопросы и изменения.
В Windows 8 используется новый процесс выбора правильного файла при возникновении конфликтов имен файлов во время копирования или перемещения.
Пользователь Л. Браун (L. Brown) сказал:
Кнопка сравнения, показывающая, идентичны ли файлы в диалоговом окне выбора, была бы очень полезной!
Зачастую имена файлов совпадают, потому что они являются копиями друг друга. Выбор между двумя идентичными файлами обычно не имеет смысла, это не требуется для операции копирования и часто не требуется для перемещения. Мы рассмотрели несколько методов определения дублирующихся файлов и решили, что проверка имени файла, размера файла и даты изменения — это самый эффективный подход. Эти атрибуты можно использовать для быстрого и эффективного выявления большинства дублирующихся файлов, при этом этот способ обладает обратной совместимостью (в отличие от других методов, таких как применение хэш-значений).
В бета-версии мы добавили новый параметр в подробное диалоговое окно разрешения конфликтов. Установив флажок в нижней левой части диалогового окна, можно отфильтровать все файлы, для которых имя, размер (до байта) и время изменения (до точности штампа времени файловой системы: 2 с для FAT, 100 нс для NTFS). Система пропустит эти файлы и не будет их копировать или перемещать. Эта функция не увеличивает время выполнения операции, работает локально и в сети во всех типах систем и хранилищ.
Мы пропустим копирование файлов с одинаковыми именами, датами и размерами
По умолчанию этот флажок не установлен (чтобы пользователи могли привыкнуть к изменившемуся интерфейсу), но после его установки выбор сохраняется.
Пользователь Джей Эл (JL) спросил:
Бывают ситуации, когда вы запускаете объемное задание копирования и понимаете, что для этого используется беспроводная сеть, и вы, спохватившись, подключаете сетевой кабель. Процесс копирования файлов знает, что нужно использовать более быстрое подключение?
Если обе стороны операции копирования — компьютеры с Windows 8, то да, процесс сможет воспользоваться более быстрым подключением благодаря улучшениям протокола SMB, позволяющим поддерживать несколько каналов.
Пользователь Тоби (Tobi) спросил:
Можно ли приостановить операцию копирования и возобновить ее после перезагрузки, перехода в спящий режим или гибернации?
В бета-версии при выходе системы из спящего режима или режима гибернации, операция копирования автоматически приостанавливается, а когда компьютер возобновляет работу, вы можете возобновить копирование, нажав кнопку приостановки. (Мы решили не возобновлять копирование автоматически, так как системная среда могла немного измениться, а мы не хотим вызвать ошибку.)
Пользователь гавикс (gawicks) попросил:
Пожалуйста, показывайте все диалоговые окна с ошибками после завершения копирования, чтобы мне не нужно было сидеть перед компьютером постоянно.
Во время задания копирования могут возникнуть два типа взаимодействия: «подтверждения» и «прерывания». Подтверждения выглядят так: «Удалить этот файл без возможности восстановления?», их нужно завершить до начала операции копирования. Прерывания — это проблемы, которые система обнаруживает во время копирования, например «Файл не найден», «Файл используется» и конфликты с именами файлов.
Система отображает все подтверждения до начала перемещения или копирования файлов. Во время копирования все прерывания ставятся в очередь и отображаются после завершения всех возможных операций. В бета-версии мы улучшили отображение подтверждений, так что теперь они не затеряются среди уже выполняющихся операций копирования.
Пользователь xpclient сказал:
Пожалуйста, исправьте печально известную ошибку с прокручиванием области навигации Windows 7.
(Дополнительные сведения см. в этом обсуждении Microsoft Answers.)
Мы исправили эту ошибку! В бета-версии ее нет.
Пользователь Раф (Raf) спросил:
Будет ли поддерживаться вращение изображения без потери качества?
В Windows 7 и Windows 8 JPEG-файлы поворачиваются без потери качества, если высота и ширина изображения делятся на 16 (стандартные размеры).
Кроме того, теперь проводник учитывает информацию об ориентации EXIF для JPEG-изображений. Если в фотоаппарате это значение задано правильно, вам редко потребуется исправлять ориентацию. В будущей записи блога мы обсудим эту возможность более подробно.
Изображения в проводнике Windows 7
Изображения в проводнике Windows 8
В Windows 8 мы продолжаем работать над увеличением производительности. Мы уделяем большое внимание задержкам и ищем способы их сокращения. В проводнике мы нашли возможность уменьшить задержки, вызванные отображением дополнительных значков.
В Windows 7 личный файл обозначается значком висячего замка. (Из-за увеличения числа общих файлов этот значок заменил значок ладони поднятой вверх для общих файлов.) Недавно мы обнаружили, что проверка этих значков увеличивала длительность тестов запуска библиотеки проводника приблизительно на 120 мс. Это вроде не очень много, но мы считаем это большой задержкой.

У дополнительных значков есть ограничения — они могут отображать только одно состояние, добавляют много визуальных помех и вызывают замешательство. Значок в виде замка был удален. Эта информация лучше воспринимается в столбце «Состояние общего доступа».
Этот столбец обладает следующими преимуществами:
К записи Марины об экране «Пуск» пользователь Boots112233 оставил следующий комментарий:
Половина элементов в меню «Пуск» Windows 7 — это ярлыки для папок и один для файла […] Как это можно сделать в Windows 8, если экран «Пуск» не позволяет использовать ярлыки для папок?
В бета-версии можно легко закрепить избранные папки в меню «Пуск» и воспользоваться преимуществами настройки для упорядочивания папок в группы в любом порядке.
«Закрепить в меню "Пуск"» на ленте проводника Windows
Кроме того, как и в Windows 7, ярлыки исполняемых файлов можно закреплять в меню «Пуск» непосредственно в проводнике Windows, что может быть очень полезно для приложений, которые по умолчанию не добавляются в меню «Пуск».
Папка Documents, пользовательский исполняемый файл и средство просмотра событий, закрепленные в меню «Пуск»
Пользователь Джейми Томсон (Jamie Thomson) сказал:
Мне очень нравится параметр «Открыть командную строку» в меню «Файл», но я предпочитаю использовать PowerShell, поэтому неплохо было бы иметь и параметр «Открыть командную строку PowerShell».
Мы согласны, поэтому добавили и этот параметр. Следует отметить, что существуют конфликтующие точки зрения о том, должны ли дополнительные функции присутствовать в графическом интерфейсе или PowerShell и где они должны отображаться. Мы всегда учитываем сложность наличия слишком большого количества параметров и многих доступных функций. Как видно, правильного ответа нет, поэтому мы продолжим искать баланс.
Кнопки Windows PowerShell в проводнике Windows
Эти элементы меню открывают консоль PowerShell. PowerShell ISE также доступна при выполнении команды «Редактировать» в файле PowerShell.
Мы ожидали, что введение ленты в проводнике вызовет горячее обсуждение, так что будет справедливо сказать, что огромное число отзывов оправдали наши ожидания. Здорово работать над чем-то, что вызывает такие разнообразные мнения.
Реакций было много и, как мы и ожидали, часть пользователей крайней отрицательно отнеслись к новой возможности, о чем они нам прямо сказали. Мы считаем, что должны развивать пользовательский интерфейс и признавать то, что часть пользователей недовольны выбранным нами направлением. Если взглянуть на проблему более широко, то подавляющее большинство пользователей довольны изменениями и благодаря им повысили эффективность работы. Напоминаем всем, что доступны средства сторонних производителей (вероятно, те, что применяют отрицательно настроенные пользователи), которые предоставляют другие варианты интерфейса. Мы хотим отметить, что сторонние средства играют важную роль для Windows.
Таким образом, мы обработали ваши отзывы, поэкспериментировали с разными подходами и использовали своих коллег как «подопытных кроликов», помимо обычного формального тестирования. В ленте бета-версии вы увидите три основных изменения.
По умолчанию лента свернута: в предварительной версии для разработчиков лента была развернута, и мы смогли узнать много о том, как люди с ней работают. Это позволило нам улучшить ленту. В бета-версии мы внесем крупное изменение, которое приведет проводник в соответствие с нашими принципами разработки Windows 8. Как и в диалоговых окнах копирования, диспетчере задач и приложениях в стиле Metro, мы будем сокращать число отвлекающих факторов и позволим пользователям самим обнаружить новые функции, свернув ленту по умолчанию.
Свернутая по умолчанию лента проводника Windows
Мы тестировали это изменение в течение некоторого времени, и результаты оказались воодушевляющими. Вот данные о внутреннем использовании в Майкрософт, которые не являются репрезентативными для широкой аудитории, но в общем случае позволяют увидеть картину на примере пользователей, с которыми вы общаетесь в этом блоге.

Эти данные показывают, что нашим технически подкованным пользователям нравится любой из параметров, но те, кто часто применяет проводник, работают с развернутой лентой. В других ситуациях с небольшим объемом операций просмотра файлов мы можем предоставить пользовательский интерфейс без отвлекающих элементов и позволить пользователям, которым нужны все функции проводника, развернуть и использовать ленту.
Видимые сочетания клавиш. Наши телеметрические данные показали, что пользователи, активно свертывающие ленту, часто применяют сочетания клавиш. Лента предоставляет новые способы доступа к функциям через клавиатуру с помощью подсказок (которые всплывают при нажатии клавиши ALT), но традиционные сочетания, такие как CTRL+V, остаются самым эффективным методом. Мы любим сочетания клавиш (у нас в компании их использование на 85% превышает применение команд проводника), поэтому мы хотим рассказать о них.
В бета-версии мы добавили сведения о сочетаниях клавиш в подсказки для соответствующих кнопок.
Подсказка для кнопки «Создать папку» с отображением сочетания клавиш
Перемещение пользовательских настроек. Мы хотели сделать так, чтобы вы настраивали проводник только один раз. Если развернуть ленту и добавить команды «Отменить и «Подключить сетевой диск» в панель быстрого доступа, то проводник должен выглядеть так же всегда.
В бета-версии мы добавили параметры проводника в атрибуты, которые перемещаются на другие компьютеры Windows 8. В интерфейсе синхронизации параметров это можно увидеть в разделе «Другие параметры Windows». (Дополнительные сведения о перемещении пользовательских настроек см. в статье Кэти.)
Синхронизация параметров проводника на нескольких компьютерах
Мы действительно ценим ваши отзывы на предыдущие записи. Мы верим в то, что они напрямую повлияли на улучшение возможностей управления файлами в Windows 8.
--Илана Смит (Ilana Smith)
Another week has passed, and we have another Friday Five to sum up some of the great contributions MVPs have made recently through articles and blog posts! This week, our MVP Friday Five is filled with even more expert knowledge that we’ve all come to expect from MVPs.
1. SSRS: Display User Data Fields for a SharePoint List
By SharePoint Server MVP Laura Rogers | @WonderLaura
Laura shows you how you can create a SQL Server Reporting Services (SSRS) report to create a better user experience for site users who fill out a list item, form or survey in SharePoint.
2. Identity crisis: Why won’t Outlook for Mac open its own messages!?
By Macintosh MVP William Smith | @meck
William addresses an issue that is common in the Microsoft Answers Outlook for Mac forum: the “Outlook cannot open the file because it is not associated with the default identity” message.
3. Big Data and SQL Server: Disruption or Harmony?
By Visual Basic MVP Andrew Brust| @andrewbrust
Andrew discusses the disruption of Big Data, Hadoop and its MapReduce distributed-computing approach has caused to SQL Server, and how Microsoft is working to create harmony between them.
By Outlook MVP Diane Poremsky | @dicot
In this article, Diane explains step by step how to disable popup messages about Exchange server messages, network warnings & network connectivity that can be annoying.
5. Removing Duplicate Dimension Rows in SSIS
By SQL Server MVP Michael J Swart | @MJSwart
In this article Michael takes you step by step through his method for solving the problem of creating a data flow transformation which removes duplicate key values in SQL Server.
If you’re an MVP and would like your blog posts considered for our MVP Friday Five, please reach out to your MVP Lead or provide your URL in the comments section below!
An error was ecnountered attempting to get the RSS data: The server did not return XML. The content type returned was text/html; charset=UTF-8
MSDN Live Developer Center. Windows Live Build compelling applications and websites using Windows Live Services.
Submit your site to Live Search. Generally our web crawler, MSNBot, can find most pages on the Internet. However if your site does not appear on Live Search, you can send us the address (URL).
Microsoft adCenter Labs Advertising information. Researchers, analysts and developers, our team cultivates exciting technologies in the areas of paid search behaviour targeting, contextual advertising, social network analysis, and image/video mining.
Silverlight helps you create rich web applications that run on Mac OS, Windows, and Linux. Welcome to a new level of engaging, rich, safe, secure, and scalable cross-platform experiences.
Phishing Filter Frequently Asked Questions
Deepfish Technology Enhances existing mobile browsing technologies by displaying content in a view that is closer to the desktop experience. Our zoom-able interface and cue map allow you to quickly access the information you care about over the web without ever losing track of where you are. From MSN Live Labs view more WAP, WML, Wireless Markup Language,WAP, WML, Wireless Markup Language, More Browser and Browser Tools
Microsoft WorldWide Telescope (WWT) is a rich visualization environment that functions as a virtual telescope, bringing together imagery from the best ground and space telescopes in the world for a seamless, guided exploration of the universe.
Microsoft Windows Windows Vista. Windows XP, etc.
Programming Applications (VBA). Using Applications
Back to top ® © ™ are owned by respective authors and websites. There may be a charge for some software. Always perform an Anti-Virus Check on any Software MSN® is a trademark of MSN Inc
Google Knowledge. Yahoo Information.
Yahoo Knowledge. Yahoo Information.
Making Money from the Internet
Search engines. Online Dictionary, Thesaurus. Acronym or abbreviation finder, etc..
TrafficSeeker. Packed with TONS of new features to get your site better rankings in the search engines. The Pro version submits your site to over 200,000 engines and the Platinum to over 1 Million engines including Google, Yahoo, HotBot, Dmoz and many more! PLUS lot's of other places >>>> Program details of how to Automatically achieve this while you sleep... Includes many powerful features to help drive traffic to your website! With more than 20 critical tools included in TrafficSeeker for optimal promotion of your website. Here are just a few: Submit Your website to more than 1.2 Million Search Engines, Directories and Link pages. Link Popularity Tracking Tool. Keyword Builder - find and use the best keywords to drive traffic to your site. HTML Validator - make sure your site is ready for search engine indexing. Website Ranking Utility. Create, Manage, Add and Edit your own search engine databases. And tons more!! Click here for more information on TrafficSeeker.
Cleverstat. Accurate Monitor for Search Engines. Free Monitor for Google. AdWords® Clever Wizard. Site Content Analyzer.
NicheBOT.com - Find what people search for. NicheBOT offers free keyword research services, innovative web site software, search engine ranking tools, and more.
![]() |
Axandra IBP. Internet Business Promoter. The all-in-one web site promotion tool for your web site success. IBP is the award-winning web site promotion and search engine submission software tool that helps you to get more revenue with high search engine rankings in Google, the new Yahoo and all other major search engines. IBP helps you with all important aspects of web site promotion. |
| Axandra ARELIS More customers, higher search engine rankings and new business contacts! ARELIS is a top rated software program that helps you to build a powerful business network quickly and easily. You'll benefit from highly targeted free traffic to your web site, new business contacts, a higher link popularity, higher search engine rankings and more sales. |
A Great Portal, Great links to great web sites. Special offers and bargains, cutting edge technology, useful business links, career links, humour, fun, sports. Computing, Freeware, Programming. Free website promotion. Lifestyle, Film, Music, Games, Entertainment, Art, Theatre, Concerts, Literature, Leisure, Days Out, Tourism, Travel and Holidays. A crazy dancing sheep and other jokes. Relaxation and stress information. Lots of various and interesting subjects. Multi-search and news headlines search. Teenager pages. Jigsaw puzzles and much more.
Advertise on A Great Portal. Paid Inclusion Targeted Traffic Listing lots of Targeted Searchable Keywords and Static Page links. Sponsored searchable links: Specific links relating to the subject matter of the site. Your details will be displayed and users will be able to search on Keywords in the Title, icons, description, specialties, extra keywords, contact details and URL you provide. We will provide you with Lots of Searchable Keywords plus Static Page links. Individually targeted for Employment, Business, Science and Technology, Computing both hardware and software Entertainment or Sport. More Website promotion. Internet advertising . DOT Solutions. Digitally Orientated Technologies. Helping people and smaller businesses increase their brand image. Low budget providers of Web & WAP (Wireless Applications Protocol) solutions. Methods of Internet adverting free tips.
DOT Solutions Helping people and smaller businesses increase their brand image. Low budget providers of Web & WAP (Wireless Applications Protocol) solutions. Also web & WAP sites promotion.
Advertising Methods FREE TIPS Advertising Methods. How to advertise online and offline. Methods of internet advertising and promotion. Here are some advertising methods that you may have considered to promote websites. Covers on-line and off-line adverting methods. The advantages and disadvantages of advertising methods and recommended ways to advertise. Don't get caught in a Mousetraps. Should you use Pixecode (Pixel Encoding), what is Pixecode (Pixel Encoding)? I've heard about Blogging, tell me more. Worried about Hidden Expenses, what are they, find out now. How about Video and Multimedia, how do I go about it and is it recommended? Lot's more FREE How much does the information cost me? It's FREE, I don't even ask for your email so don't worry about being added to Spam list and no need to register to get this FREE information. information, tips and advice.
Best selling Internet Items from Amazon
Two simple steps to higher search engine placement
|
|
More Search engines. Online Dictionary, Thesaurus. Acronym or abbreviation finder, etc..
More Programming Languages and Computer Code and Scripting
NicheBOT.com - Find what people search for. NicheBOT offers free keyword research services, innovative web site software, search engine ranking tools, and more.
Top websites. Domains Top Address. Find or sell domain names. Want to sell a Domain Name? Want to make money from a unused domain name you own? Only pay on a sale. Need to find a domain name for your business? Search now!
Web site promotion and traffic boosting Big list of Submission sites
Also view our Web site promotion and traffic boosting section.
Benefit from IT Web and PC design and development.
Forums. Computing Forums. Webmaster Forums, Programming Forums
Hosting Question you should ask
Apache open-source software and Apache Servers. Mod Rewrite.
.htaccess Files and .htaccess Help. How use to .htaccess
CRON scheduler running of programs. CRONTABS
Scams and hoaxes. Fraud warnings. Virus Attacks
Diagnostics and Security (Phishing information)
Backup/File Compression Data Recovery
Protect your Usernames and passwords. Protect your system
Disaster Recovery Planning. (Also Undelete Files) So how good is your Disaster Recovery Planning?
Anti-Virus Software Tools & Utilities
Programming Applications (VBA). Using Applications.
Top websites. Domains Top Address. Find or sell domain names. Want to sell a Domain Name? Want to make money from a unused domain name you own? Only pay on a sale. Need to find a domain name for your business? Search now!
DOT Solutions. Digitally Orientated Technologies bring you Targeted Traffic for your site. Helping people and smaller businesses increase their brand image. Using low budget methods. Able to provide step by step WAP (mobile phone) and WEB advertising solutions. This method is ideal for people or businesses with smaller budgets.
Advertise on A Great Portal. Paid Inclusion Targeted Traffic Listing lots of Targeted Searchable Keywords and Static Page links. Sponsored searchable links: Specific links relating to the subject matter of the site. Your details will be displayed and users will be able to search on Keywords in the Title, icons, description, specialties, extra keywords, contact details and URL you provide. We will provide you with Lots of Searchable Keywords plus Static Page links. Individually targeted for Employment, Business, Science and Technology, Computing both hardware and software Entertainment or Sport. More Website promotion. Internet advertising . DOT Solutions. Digitally Orientated Technologies. Helping people and smaller businesses increase their brand image. Low budget providers of Web & WAP (Wireless Applications Protocol) solutions. Methods of Internet adverting free tips.
A Computer Portal. Site Map
Site Map in XML of this site. Using ROR (Resources Of a Resource) is a rapidly growing XML format for describing any object on a website (sitemaps, products, services, menus, images, reviews, contact info, business info, etc), so any search engines can better understand its content. ROR Sitemap Generator ROR Submission More information about Site Maps and Google Site Maps
Back to top ® © ™ are owned by respective authors and websites. There may be a charge for some software. Always perform an Anti-Virus Check on any Software
Web Masters. Click Here Now to start making money. A Great opportunity to make some money. Receive 50% by offering your users Ton's of Keywords on A Great Portal websites. Our Affiliate Program Pays you 50% on Level 1 of Every Sale of our Text Link both searchable and static Text Link!
Compare Bargains. Discounts and special offers. Compare Bargains Domain Name for Sale, URL, for Sale. http://www.comparebargains.com A domain name to make money from.
A Computer Portal. Freeware, Shareware. Download software. Computer languages and Programming code. Including PERL Scripts and Java Scripts. Webmaster Tools. Internet Marketing, Website promotion. Hardware Help from BIOS to Windows and UNIX.
® © ™ are owned by respective authors and websites. There may be a charge for some software. Google™ is a trademark of Google Inc, These pages are not endorsed by Google or any other Company. Always perform an Anti-Virus Check on any Software